#!/usr/bin/env bash
#===--- build-script-impl - Implementation details of build-script ---------===#
#
## This source file is part of the Swift.org open source project
##
## Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
## Licensed under Apache License v2.0 with Runtime Library Exception
##
## See http://swift.org/LICENSE.txt for license information
## See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
#===------------------------------------------------------------------------===#

#
# This script is an implementation detail of other build scripts and should not
# be called directly.
#
# Note: This script will NOT auto-clean before building.
#

set -o pipefail
set -e

umask 0022

# Declare the set of known settings along with each one's description
#
# If you add a user-settable variable, add it to this list.
#
# A default value of "" indicates that the corresponding variable
# will remain unset unless set explicitly.
#
# skip-* parameters do not affect the configuration (CMake parameters).
# You can turn them on and off in different invocations of the script for the
# same build directory.
#
# build-* parameters affect the CMake configuration (enable/disable those
# components).
#
# Each variable name is re-exported into this script in uppercase, where dashes
# are substituted by underscores. For example, `swift-install-components` is
# referred to as `SWIFT_INSTALL_COMPONENTS` in the remainder of this script.
KNOWN_SETTINGS=(
    # name                      default          description
    dry-run                     ""               "print the commands that would be executed, but do not execute them"
    build-args                  ""               "arguments to the build tool; defaults to -j8 when CMake generator is \"Unix Makefiles\""
    build-dir                   ""               "out-of-tree build directory; default is in-tree. **This argument is required**"
    host-cc                     ""               "the path to CC, the 'clang' compiler for the host platform. **This argument is required**"
    host-cxx                    ""               "the path to CXX, the 'clang++' compiler for the host platform. **This argument is required**"
    darwin-xcrun-toolchain      "default"        "the name of the toolchain to use on Darwin"
    ninja-bin                   ""               "the path to Ninja tool"
    cmark-build-type            "Debug"          "the CMake build variant for CommonMark (Debug, RelWithDebInfo, Release, MinSizeRel).  Defaults to Debug."
    lldb-extra-cmake-args       ""               "extra command line args to pass to lldb cmake"
    lldb-extra-xcodebuild-args  ""               "extra command line args to pass to lldb xcodebuild"
    lldb-test-cc                ""               "CC to use for building LLDB testsuite test inferiors.  Defaults to just-built, in-tree clang.  If set to 'host-toolchain', sets it to same as host-cc."
    lldb-test-with-curses       ""               "run test lldb test runner using curses terminal control"
    lldb-test-swift-only        ""               "when running lldb tests, only include Swift-specific tests"
    lldb-no-debugserver         ""               "delete debugserver after building it, and don't try to codesign it"
    lldb-use-system-debugserver ""               "don't try to codesign debugserver, and use the system's debugserver instead"
    llvm-build-type             "Debug"          "the CMake build variant for LLVM and Clang (Debug, RelWithDebInfo, Release, MinSizeRel).  Defaults to Debug."
    swift-build-type            "Debug"          "the CMake build variant for Swift"
    swift-enable-assertions     "1"              "enable assertions in Swift"
    swift-analyze-code-coverage "not-merged"     "Code coverage analysis mode for Swift (false, not-merged, merged). Defaults to false if the argument is not present, and not-merged if the argument is present without a modifier."
    swift-tools-enable-lto      ""               "enable LTO compilation of Swift tools. *NOTE* This does not include the swift standard library and runtime. Must be set to one of 'thin' or 'full'"
    llvm-enable-lto             ""               "Must be set to one of 'thin' or 'full'"
    llvm-enable-modules         "1"              "enable building llvm using modules"
    swift-tools-num-parallel-lto-link-jobs ""    "The number of parallel link jobs to use when compiling swift tools"
    llvm-num-parallel-lto-link-jobs ""           "The number of parallel link jobs to use when compiling llvm"
    swift-stdlib-build-type     "Debug"          "the CMake build variant for Swift"
    swift-stdlib-enable-assertions "1"           "enable assertions in Swift"
    swift-stdlib-enable-resilience "0"           "build the Swift stdlib and overlays with resilience enabled"
    swift-stdlib-sil-serialize-all "1"           "build the Swift stdlib and overlays with all method bodies serialized"
    lldb-build-type             "Debug"          "the CMake build variant for LLDB"
    llbuild-build-type          "Debug"          "the CMake build variant for llbuild"
    foundation-build-type       "Debug"          "the build variant for Foundation"
    libdispatch-build-type      "Debug"          "the build variant for libdispatch"
    playgroundlogger-build-type "Debug"          "the build variant for PlaygroundLogger"
    playgroundsupport-build-type "Debug"         "the build variant for PlaygroundSupport"
    xctest-build-type           "Debug"          "the build variant for xctest"
    llbuild-enable-assertions   "1"              "enable assertions in llbuild"
    enable-asan                 ""               "enable Address Sanitizer"
    cmake                       ""               "path to the cmake binary"
    distcc                      ""               "use distcc in pump mode"
    distcc-pump                 ""               "the path to distcc pump executable. This argument is required if distcc is set."
    build-runtime-with-host-compiler   "1"       "use the host c++ compiler to build everything"
    cmake-generator             "Unix Makefiles" "kind of build system to generate; see output of 'cmake --help' for choices"
    verbose-build               ""               "print the commands executed during the build"
    install-prefix              ""               "installation prefix"
    toolchain-prefix            ""               "the path to the .xctoolchain directory that houses the install prefix path"
    install-destdir             ""               "the path to use as the filesystem root for the installation"
    install-symroot             ""               "the path to install debug symbols into"
    swift-install-components    ""               "a semicolon-separated list of Swift components to install"
    llvm-install-components    ""                "a semicolon-separated list of LLVM components to install"
    installable-package         ""               "the path to the archive of the installation directory"
    test-installable-package    ""               "whether to run post-packaging tests on the produced package"
    reconfigure                 ""               "force a CMake configuration run even if CMakeCache.txt already exists"
    swift-primary-variant-sdk   ""               "default SDK for target binaries"
    swift-primary-variant-arch  ""               "default arch for target binaries"
    skip-build-cmark            ""               "set to skip building CommonMark"
    skip-build-llvm             ""               "set to skip building LLVM/Clang"
    skip-build-compiler-rt      ""               "set to skip building Compiler-RT"
    skip-build-swift            ""               "set to skip building Swift"
    skip-build-linux            ""               "set to skip building Swift stdlibs for Linux"
    skip-build-freebsd          ""               "set to skip building Swift stdlibs for FreeBSD"
    skip-build-cygwin           ""               "set to skip building Swift stdlibs for Cygwin"
    skip-build-osx              ""               "set to skip building Swift stdlibs for OS X"
    skip-build-ios-device       ""               "set to skip building Swift stdlibs for iOS devices (i.e. build simulators only)"
    skip-build-ios-simulator    ""               "set to skip building Swift stdlibs for iOS simulators (i.e. build devices only)"
    skip-build-tvos-device      ""               "set to skip building Swift stdlibs for tvOS devices (i.e. build simulators only)"
    skip-build-tvos-simulator   ""               "set to skip building Swift stdlibs for tvOS simulators (i.e. build devices only)"
    skip-build-watchos-device   ""               "set to skip building Swift stdlibs for Apple watchOS devices (i.e. build simulators only)"
    skip-build-watchos-simulator ""              "set to skip building Swift stdlibs for Apple watchOS simulators (i.e. build devices only)"
    skip-build-android          ""               "set to skip building Swift stdlibs for Android"
    skip-build-lldb             ""               "set to skip building LLDB"
    skip-build-llbuild          ""               "set to skip building llbuild"
    skip-build-swiftpm          ""               "set to skip building swiftpm"
    skip-build-xctest           ""               "set to skip building xctest"
    skip-build-foundation       ""               "set to skip building foundation"
    skip-build-libdispatch      ""               "set to skip building libdispatch"
    skip-build-benchmarks       ""               "set to skip building Swift Benchmark Suite"
    skip-build-playgroundlogger ""               "set to skip building PlaygroundLogger"
    skip-build-playgroundsupport ""              "set to skip building PlaygroundSupport"
    skip-test-cmark             ""               "set to skip testing CommonMark"
    skip-test-lldb              ""               "set to skip testing lldb"
    skip-test-swift             ""               "set to skip testing Swift"
    skip-test-llbuild           ""               "set to skip testing llbuild"
    skip-test-swiftpm           ""               "set to skip testing swiftpm"
    skip-test-xctest            ""               "set to skip testing xctest"
    skip-test-foundation        ""               "set to skip testing foundation"
    skip-test-libdispatch       ""               "set to skip testing libdispatch"
    skip-test-playgroundlogger  ""               "set to skip testing PlaygroundLogger"
    skip-test-playgroundsupport ""               "set to skip testing PlaygroundSupport"
    skip-test-linux             ""               "set to skip testing Swift stdlibs for Linux"
    skip-test-freebsd           ""               "set to skip testing Swift stdlibs for FreeBSD"
    skip-test-cygwin            ""               "set to skip testing Swift stdlibs for Cygwin"
    skip-test-osx               ""               "set to skip testing Swift stdlibs for OS X"
    skip-test-ios-simulator     ""               "set to skip testing Swift stdlibs for iOS simulators (i.e. test devices only)"
    skip-test-ios-host          ""               "set to skip testing the host parts of the iOS toolchain"
    skip-test-tvos-simulator    ""               "set to skip testing Swift stdlibs for tvOS simulators (i.e. test devices only)"
    skip-test-tvos-host         ""               "set to skip testing the host parts of the tvOS toolchain"
    skip-test-watchos-simulator  ""              "set to skip testing Swift stdlibs for Apple watchOS simulators (i.e. test devices only)"
    skip-test-watchos-host      ""               "set to skip testing the host parts of the watchOS toolchain"
    skip-test-android-host      ""               "set to skip testing the host parts of the Android toolchain"
    validation-test             "0"              "set to run the validation test suite"
    long-test                   "0"              "set to run the long test suite"
    skip-test-benchmarks        ""               "set to skip running Swift Benchmark Suite"
    skip-test-optimized         ""               "set to skip testing the test suite in optimized mode"
    stress-test-sourcekit       ""               "set to run the stress-SourceKit target"
    workspace                   "${HOME}/src"    "source directory containing llvm, clang, swift"
    enable-llvm-assertions      "1"              "set to enable llvm assertions"
    build-llvm                  "1"              "set to 1 to build LLVM and Clang"
    build-swift-tools           "1"              "set to 1 to build Swift host tools"
    build-swift-dynamic-stdlib  ""               "set to 1 to build dynamic variants of the Swift standard library"
    build-swift-static-stdlib   ""               "set to 1 to build static variants of the Swift standard library"
    build-swift-stdlib-unittest-extra "0"        "set to 1 to build optional StdlibUnittest components"
    build-swift-dynamic-sdk-overlay   ""         "set to 1 to build dynamic variants of the Swift SDK overlay"
    build-swift-static-sdk-overlay    ""         "set to 1 to build static variants of the Swift SDK overlay"
    build-swift-examples        "1"              "set to 1 to build examples"
    build-swift-remote-mirror   "1"              "set to 1 to build the Swift Remote Mirror library"
    build-serialized-stdlib-unittest "0"         "set to 1 to build the StdlibUnittest module with -sil-serialize-all"
    build-sil-debugging-stdlib  "0"              "set to 1 to build the Swift standard library with -gsil to enable debugging and profiling on SIL level"
    check-incremental-compilation "0"            "set to 1 to compile swift libraries multiple times to check if incremental compilation works"
    llvm-include-tests          "1"              "Set to true to generate testing targets for LLVM. Set to true by default."
    swift-include-tests         "1"              "Set to true to generate testing targets for Swift. This allows the build to proceed when 'test' directory is missing (required for B&I builds)"
    native-llvm-tools-path      ""               "directory that contains LLVM tools that are executable on the build machine"
    native-clang-tools-path     ""               "directory that contains Clang tools that are executable on the build machine"
    native-swift-tools-path     ""               "directory that contains Swift tools that are executable on the build machine"
    compiler-vendor             "none"           "compiler vendor name [none,apple]"
    clang-user-visible-version  "3.8.0"          "user-visible version of the embedded Clang and LLVM compilers"
    swift-user-visible-version  "3.0"            "user-visible version of the Swift language"
    swift-compiler-version      ""               "string that indicates a compiler version for Swift"
    clang-compiler-version      ""               "string that indicates a compiler version for Clang"
    embed-bitcode-section       "0"              "embed an LLVM bitcode section in stdlib/overlay binaries for supported platforms"
    darwin-crash-reporter-client ""              "whether to enable CrashReporter integration"
    darwin-stdlib-install-name-dir ""            "the directory of the install_name for standard library dylibs"
    install-cmark               ""               "whether to install cmark"
    install-swift               ""               "whether to install Swift"
    install-lldb                ""               "whether to install LLDB"
    install-llbuild             ""               "whether to install llbuild"
    install-swiftpm             ""               "whether to install swiftpm"
    install-xctest              ""               "whether to install xctest"
    install-foundation          ""               "whether to install foundation"
    install-libdispatch         ""               "whether to install libdispatch"
    install-playgroundlogger    ""               "whether to install PlaygroundLogger"
    install-playgroundsupport   ""               "whether to install PlaygroundSupport"
    darwin-install-extract-symbols ""            "whether to extract symbols with dsymutil during installations"
    host-target                 ""               "The host target. LLVM, Clang, and Swift will be built for this target. The built LLVM and Clang will be used to compile Swift for the cross-compilation targets. **This argument is required**"
    stdlib-deployment-targets   ""               "space-separated list of targets to configure the Swift standard library to be compiled or cross-compiled for"
    build-stdlib-deployment-targets "all"        "space-separated list that filters which of the configured targets to build the Swift standard library for, or 'all'"
    cross-compile-hosts         ""               "space-separated list of targets to cross-compile host Swift tools for"
    cross-compile-with-host-tools  ""            "set to use the clang we build for the host to then build the cross-compile hosts"
    cross-compile-install-prefixes      ""       "semicolon-separated list of install prefixes to use for the cross-compiled hosts. The list expands, so if there are more cross-compile hosts than prefixes, unmatched hosts use the last prefix in the list"
    skip-merge-lipo-cross-compile-tools ""       "set to skip running merge-lipo after installing cross-compiled host Swift tools"
    darwin-deployment-version-osx     "10.9"     "minimum deployment target version for OS X"
    darwin-deployment-version-ios     "7.0"      "minimum deployment target version for iOS"
    darwin-deployment-version-tvos    "9.0"      "minimum deployment target version for tvOS"
    darwin-deployment-version-watchos "2.0"      "minimum deployment target version for watchOS"
    extra-cmake-options         ""               "Extra options to pass to CMake for all targets"
    extra-swift-args            ""               "Extra arguments to pass to swift modules which match regex. Assumed to be a flattened cmake list consisting of [module_regexp, args, module_regexp, args, ...]"
    sil-verify-all              "0"              "If enabled, run the SIL verifier after each transform when building Swift files during this build process"
    swift-enable-ast-verifier   "1"              "If enabled, and the assertions are enabled, the built Swift compiler will run the AST verifier every time it is invoked"
    swift-runtime-enable-leak-checker   "0"              "Enable leaks checking routines in the runtime"
    use-gold-linker             ""               "Enable using the gold linker"
    darwin-toolchain-bundle-identifier ""        "CFBundleIdentifier for xctoolchain info plist"
    darwin-toolchain-display-name      ""        "Display Name for xctoolcain info plist"
    darwin-toolchain-display-name-short ""       "Display Name with out date for xctoolchain info plist"
    darwin-toolchain-name              ""        "Directory name for xctoolchain"
    darwin-toolchain-version           ""        "Version for xctoolchain info plist and installer pkg"
    darwin-toolchain-application-cert  ""        "Application Cert name to codesign xctoolchain"
    darwin-toolchain-installer-cert    ""        "Installer Cert name to create installer pkg"
    darwin-toolchain-installer-package ""        "The path to installer pkg"
    build-jobs                         ""        "The number of parallel build jobs to use"
    darwin-toolchain-alias             ""        "Swift alias for toolchain"
    android-ndk                        ""        "An absolute path to the NDK that will be used as a libc implementation for Android builds"
    android-api-level                  ""        "The Android API level to target when building for Android. Currently only 21 or above is supported"
    android-ndk-gcc-version            ""        "The GCC version to use when building for Android. Currently only 4.9 is supported"
    android-icu-uc                     ""        "Path to a directory containing libicuuc.so"
    android-icu-uc-include             ""        "Path to a directory containing headers for libicuuc"
    android-icu-i18n                   ""        "Path to a directory containing libicui18n.so"
    android-icu-i18n-include           ""        "Path to a directory containing headers libicui18n"
    android-deploy-device-path         ""        "Path on an Android device to which built Swift stdlib products will be deployed"
    check-args-only                    ""        "set to check all arguments are known. Exit with status 0 if success, non zero otherwise"
    common-cmake-options               ""        "CMake options used for all targets, including LLVM/Clang"
    cmark-cmake-options                ""        "CMake options used for all cmark targets"
    ninja-cmake-options                ""        "CMake options used for all ninja targets"
    foundation-cmake-options           ""        "CMake options used for all foundation targets"
    libdispatch-cmake-options          ""        "CMake options used for all libdispatch targets"
    llbuild-cmake-options              ""        "CMake options used for all llbuild targets"
    lldb-cmake-options                 ""        "CMake options used for all lldb targets"
    llvm-cmake-options                 ""        "CMake options used for all llvm targets"
    ninja-cmake-options                ""        "CMake options used for all ninja targets"
    swift-cmake-options                ""        "CMake options used for all swift targets"
    swiftpm-cmake-options              ""        "CMake options used for all swiftpm targets"
    xctest-cmake-options               ""        "CMake options used for all xctest targets"
    playgroundsupport-cmake-options    ""        "CMake options used for all playgroundsupport targets"
    playgroundlogger-cmake-options     ""        "CMake options used for all playgroundlogger targets"
    # TODO: Remove this some time later.
    user-config-args            ""               "**Renamed to --extra-cmake-options**: User-supplied arguments to cmake when used to do configuration."
    only-execute                       "all"     "Only execute the named action (see implementation)"
    llvm-lit-args                      ""        "If set, override the lit args passed to LLVM"
    clang-profile-instr-use            ""        "If set, profile file to use for clang PGO"
    coverage-db                        ""        "If set, coverage database to use when prioritizing testing"
    build-toolchain-only               ""        "If set, only build the necessary tools to build an external toolchain"
    skip-local-host-install            ""        "If we are cross-compiling multiple targets, skip an install pass locally if the hosts match"
)

# Centralized access point for traced command invocation.
# Every operation that might mutates file system should be called via
# these functions.

function call() {
    if [[ ${DRY_RUN} ]]; then
        echo "${PS4}"$(quoted_print "$@")
    else
        { set -x; } 2>/dev/null
        "$@"
        { set +x; } 2>/dev/null
    fi
}

function with_pushd() {
    local dir=$1
    shift
    if [[ "$1" == "call" ]]; then
        shift
    fi
    if [[ ${DRY_RUN} ]]; then
        echo ${PS4}pushd "${dir}"
        echo "${PS4}"$(quoted_print "$@")
        echo ${PS4}popd
    else
        set -x
        pushd "${dir}"
        "$@"
        { set -x; } 2>/dev/null # because $@ might includes { set +x; }
        popd
        { set +x; } 2>/dev/null
    fi
}

function quoted_print() {
    python -c 'import pipes; import sys; print(" ".join(pipes.quote(arg) for arg in sys.argv[1:]))' "$@"
}

function toupper() {
    echo "$@" | tr '[:lower:]' '[:upper:]'
}

function tolower() {
    echo "$@" | tr '[:upper:]' '[:lower:]'
}

function true_false() {
    case "$1" in
        false | FALSE | 0 | "")
            echo "FALSE"
            ;;
        true | TRUE | 1)
            echo "TRUE"
            ;;
        *)
            echo "true_false: unknown value: $1" >&2
            exit 1
            ;;
    esac
}

function to_varname() {
    toupper "${1//-/_}"
}

function set_lldb_build_mode() {
    LLDB_BUILD_MODE="CustomSwift-${LLDB_BUILD_TYPE}"
}

function is_llvm_lto_enabled() {
    if [[ "${LLVM_ENABLE_LTO}" == "thin" ]] ||
       [[ "${LLVM_ENABLE_LTO}" == "full" ]]; then
        echo "TRUE"
    else
        echo "FALSE"
    fi
}

function is_swift_lto_enabled() {
    if [[ "${SWIFT_TOOLS_ENABLE_LTO}" == "thin" ]] ||
       [[ "${SWIFT_TOOLS_ENABLE_LTO}" == "full" ]]; then
        echo "TRUE"
    else
        echo "FALSE"
    fi
}

# Enable module-builds of llvm only when asan is disabled.
# FIXME: rdar://problem/28356072
function is_llvm_module_build_enabled() {
    if [[ "$(true_false ${LLVM_ENABLE_MODULES})" == "TRUE" ]] &&
       [[ "$(true_false ${ENABLE_ASAN})" == "FALSE" ]]; then
        echo "TRUE"
    else
        echo "FALSE"
    fi
}

# Support for performing isolated actions.
#
# This is part of refactoring more work to be done or controllable via
# `build-script` itself. For additional information, see:
# https://bugs.swift.org/browse/SR-237
#
# To use this functionality, the script is invoked with:
#   ONLY_EXECUTE=<action name>
# where <action name> is one of:
#   all                          -- execute all actions
#   ${host}-${product}-build     -- the build of the product
#   ${host}-${product}-test      -- the test of the product
#   ${host}-${product}-install   -- the install of the product
#   ${host}-package              -- the package construction and test
#   merged-hosts-lipo            -- the lipo step, if used
# and if used, only the one individual action will be performed.
#
# If not set, the default is `all`.

# should_execute_action(name) -> 1 or nil
#
# Check if the named action should be run in the given script invocation.
function should_execute_action() {
    local name="$1"
    
    if [[ "${ONLY_EXECUTE}" = "all" ]] ||
           [[ "${ONLY_EXECUTE}" = "${name}" ]]; then
        echo 1
    fi
}

# should_execute_host_actions_for_phase(host, phase-name) -> 1 or nil
#
# Check if the there are any actions to execute for this host and phase (i.e.,
# "build", "test", or "install")
function should_execute_host_actions_for_phase() {
    local host="$1"
    local phase_name="$2"

    if [[ "${ONLY_EXECUTE}" = "all" ]] ||
           [[ "${ONLY_EXECUTE}" == ${host}-*-${phase_name} ]]; then
        echo 1
    fi
}

function set_build_options_for_host() {
    llvm_cmake_options=()
    swift_cmake_options=()
    cmark_cmake_options=()
    lldb_cmake_options=()
    swiftpm_bootstrap_options=()
    SWIFT_HOST_VARIANT=
    SWIFT_HOST_VARIANT_SDK=
    SWIFT_HOST_VARIANT_ARCH=
    SWIFT_HOST_TRIPLE=
    USE_GOLD_LINKER=
    local host="$1"

    # Hosts which can be cross-compiled must specify:
    # SWIFT_HOST_TRIPLE and llvm_target_arch (as well as usual HOST_VARIANT flags)
    
    case ${host} in
        freebsd-x86_64)
            SWIFT_HOST_VARIANT="freebsd"
            SWIFT_HOST_VARIANT_SDK="FREEBSD"
            SWIFT_HOST_VARIANT_ARCH="x86_64"
            ;;
        cygwin-x86_64)
            SWIFT_HOST_VARIANT="windows"
            SWIFT_HOST_VARIANT_SDK="CYGWIN"
            SWIFT_HOST_VARIANT_ARCH="x86_64"
            ;;
        linux-*)
            SWIFT_HOST_VARIANT="linux"
            SWIFT_HOST_VARIANT_SDK="LINUX"
            USE_GOLD_LINKER=1
            case ${host} in
                linux-x86_64)
                    SWIFT_HOST_VARIANT_ARCH="x86_64"
                    playgroundlogger_build_cmd="${PLAYGROUNDLOGGER_SOURCE_DIR}/build.py"
                    playgroundlogger_build_options=(
                        --swiftc "$(build_directory_bin ${host} swift)"
                        --foundation "$(build_directory ${host} foundation)"
                        --build-dir "$(build_directory ${host} playgroundlogger)"
                        --swift-build-dir "$(build_directory ${host} swift)"
                        --$(tolower "${PLAYGROUNDLOGGER_BUILD_TYPE}")
                    )
                    ;;
                linux-armv6)
                    SWIFT_HOST_VARIANT_ARCH="armv6"
                    SWIFT_HOST_TRIPLE="armv6-unknown-linux-gnueabihf"
                    llvm_target_arch="ARM"
                    ;;
                linux-armv7)
                    SWIFT_HOST_VARIANT_ARCH="armv7"
                    SWIFT_HOST_TRIPLE="armv7-unknown-linux-gnueabihf"
                    llvm_target_arch="ARM"
                    ;;
                linux-aarch64)
                    SWIFT_HOST_VARIANT_ARCH="aarch64"
                    ;;
                linux-powerpc64)
                    SWIFT_HOST_VARIANT_ARCH="powerpc64"
                    ;;
                linux-powerpc64le)
                    SWIFT_HOST_VARIANT_ARCH="powerpc64le"
                    ;;
                linux-s390x)
                    SWIFT_HOST_VARIANT_ARCH="s390x"
                    ;;
                esac
        ;;
        macosx-* | iphoneos-* | iphonesimulator-* | \
          appletvos-* | appletvsimulator-* | \
            watchos-* | watchsimulator-*)
            case ${host} in
                macosx-x86_64)
                    xcrun_sdk_name="macosx"
                    llvm_target_arch=""
                    SWIFT_HOST_TRIPLE="x86_64-apple-macosx${DARWIN_DEPLOYMENT_VERSION_OSX}"
                    SWIFT_HOST_VARIANT="macosx"
                    SWIFT_HOST_VARIANT_SDK="OSX"
                    SWIFT_HOST_VARIANT_ARCH="x86_64"

                    cmake_osx_deployment_target="${DARWIN_DEPLOYMENT_VERSION_OSX}"
                    cmark_cmake_options=(
                        -DCMAKE_C_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                        -DCMAKE_OSX_DEPLOYMENT_TARGET="${cmake_osx_deployment_target}"
                    )
                    swiftpm_bootstrap_options=(
                        --sysroot="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                    )
                    playgroundlogger_build_cmd="xcodebuild"
                    playgroundlogger_build_target=("PlaygroundLogger_TestDriver")
                    PLAYGROUNDLOGGER_INSTALL_PLATFORM="MacOSX.platform"
                    ;;
                iphonesimulator-i386)
                    xcrun_sdk_name="iphonesimulator"
                    llvm_target_arch="X86"
                    SWIFT_HOST_TRIPLE="i386-apple-ios${DARWIN_DEPLOYMENT_VERSION_IOS}"
                    SWIFT_HOST_VARIANT="iphonesimulator"
                    SWIFT_HOST_VARIANT_SDK="IOS_SIMULATOR"
                    SWIFT_HOST_VARIANT_ARCH="i386"

                    cmake_osx_deployment_target=""
                    cmark_cmake_options=(
                        -DCMAKE_C_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                    )
                    playgroundlogger_build_cmd="xcodebuild"
                    playgroundlogger_build_target=("PlaygroundLogger_iOS")
                    PLAYGROUNDLOGGER_INSTALL_PLATFORM="iPhoneSimulator.platform"
                    ;;
                iphonesimulator-x86_64)
                    xcrun_sdk_name="iphonesimulator"
                    llvm_target_arch="X86"
                    SWIFT_HOST_TRIPLE="x86_64-apple-ios${DARWIN_DEPLOYMENT_VERSION_IOS}"
                    SWIFT_HOST_VARIANT="iphonesimulator"
                    SWIFT_HOST_VARIANT_SDK="IOS_SIMULATOR"
                    SWIFT_HOST_VARIANT_ARCH="x86_64"
                    
                    cmake_osx_deployment_target=""
                    cmark_cmake_options=(
                        -DCMAKE_C_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                    )
                    playgroundlogger_build_cmd="xcodebuild"
                    playgroundlogger_build_target=("PlaygroundLogger_iOS")
                    PLAYGROUNDLOGGER_INSTALL_PLATFORM="iPhoneSimulator.platform"
                    ;;
                iphoneos-armv7)
                    xcrun_sdk_name="iphoneos"
                    llvm_target_arch="ARM"
                    SWIFT_HOST_TRIPLE="armv7-apple-ios${DARWIN_DEPLOYMENT_VERSION_IOS}"
                    SWIFT_HOST_VARIANT="iphoneos"
                    SWIFT_HOST_VARIANT_SDK="IOS"
                    SWIFT_HOST_VARIANT_ARCH="armv7"
                    
                    cmake_osx_deployment_target=""
                    cmark_cmake_options=(
                        -DCMAKE_C_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                    )
                    playgroundlogger_build_cmd="xcodebuild"
                    playgroundlogger_build_target=("PlaygroundLogger_iOS")
                    PLAYGROUNDLOGGER_INSTALL_PLATFORM="iPhoneOS.platform"
                    ;;
                iphoneos-armv7s)
                    xcrun_sdk_name="iphoneos"
                    llvm_target_arch="ARM"
                    SWIFT_HOST_TRIPLE="armv7s-apple-ios${DARWIN_DEPLOYMENT_VERSION_IOS}"
                    SWIFT_HOST_VARIANT="iphoneos"
                    SWIFT_HOST_VARIANT_SDK="IOS"
                    SWIFT_HOST_VARIANT_ARCH="armv7s"

                    cmake_osx_deployment_target=""
                    cmark_cmake_options=(
                        -DCMAKE_C_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                    )
                    playgroundlogger_build_cmd="xcodebuild"
                    playgroundlogger_build_target=("PlaygroundLogger_iOS")
                    PLAYGROUNDLOGGER_INSTALL_PLATFORM="iPhoneOS.platform"
                    ;;
                iphoneos-arm64)
                    xcrun_sdk_name="iphoneos"
                    llvm_target_arch="AArch64"
                    SWIFT_HOST_TRIPLE="arm64-apple-ios${DARWIN_DEPLOYMENT_VERSION_IOS}"
                    SWIFT_HOST_VARIANT="iphoneos"
                    SWIFT_HOST_VARIANT_SDK="IOS"
                    SWIFT_HOST_VARIANT_ARCH="arm64"

                    cmake_osx_deployment_target=""
                    cmark_cmake_options=(
                        -DCMAKE_C_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                    )
                    playgroundlogger_build_cmd="xcodebuild"
                    playgroundlogger_build_target=("PlaygroundLogger_iOS")
                    PLAYGROUNDLOGGER_INSTALL_PLATFORM="iPhoneOS.platform"
                    ;;
                appletvsimulator-x86_64)
                    xcrun_sdk_name="appletvsimulator"
                    llvm_target_arch="X86"
                    SWIFT_HOST_TRIPLE="x86_64-apple-tvos${DARWIN_DEPLOYMENT_VERSION_TVOS}"
                    SWIFT_HOST_VARIANT="appletvsimulator"
                    SWIFT_HOST_VARIANT_SDK="TVOS_SIMULATOR"
                    SWIFT_HOST_VARIANT_ARCH="x86_64"
                    
                    cmake_osx_deployment_target=""
                    cmark_cmake_options=(
                        -DCMAKE_C_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                    )
                    playgroundlogger_build_cmd="xcodebuild"
                    playgroundlogger_build_target=("PlaygroundLogger_tvOS")
                    PLAYGROUNDLOGGER_INSTALL_PLATFORM="AppleTVSimulator.platform"
                    ;;
                appletvos-arm64)
                    xcrun_sdk_name="appletvos"
                    llvm_target_arch="AArch64"
                    SWIFT_HOST_TRIPLE="arm64-apple-tvos${DARWIN_DEPLOYMENT_VERSION_TVOS}"
                    SWIFT_HOST_VARIANT="appletvos"
                    SWIFT_HOST_VARIANT_SDK="TVOS"
                    SWIFT_HOST_VARIANT_ARCH="arm64"

                    cmake_osx_deployment_target=""
                    cmark_cmake_options=(
                        -DCMAKE_C_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                    )
                    playgroundlogger_build_cmd="xcodebuild"
                    playgroundlogger_build_target=("PlaygroundLogger_tvOS")
                    PLAYGROUNDLOGGER_INSTALL_PLATFORM="AppleTVOS.platform"
                    ;;
                watchsimulator-i386)
                    xcrun_sdk_name="watchsimulator"
                    llvm_target_arch="X86"
                    SWIFT_HOST_TRIPLE="i386-apple-watchos${DARWIN_DEPLOYMENT_VERSION_WATCHOS}"
                    SWIFT_HOST_VARIANT="watchsimulator"
                    SWIFT_HOST_VARIANT_SDK="WATCHOS_SIMULATOR"
                    SWIFT_HOST_VARIANT_ARCH="i386"

                    cmake_osx_deployment_target=""
                    cmark_cmake_options=(
                        -DCMAKE_C_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                    )
                    ;;
                watchos-armv7k)
                    xcrun_sdk_name="watchos"
                    llvm_target_arch="ARM"
                    SWIFT_HOST_TRIPLE="armv7k-apple-watchos${DARWIN_DEPLOYMENT_VERSION_WATCHOS}"
                    SWIFT_HOST_VARIANT="watchos"
                    SWIFT_HOST_VARIANT_SDK="WATCHOS"
                    SWIFT_HOST_VARIANT_ARCH="armv7k"

                    cmake_osx_deployment_target=""
                    cmark_cmake_options=(
                        -DCMAKE_C_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_CXX_FLAGS="$(cmark_c_flags ${host})"
                        -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                    )
                    ;;
                *)
                    echo "Unknown host for swift tools: ${host}"
                    exit 1
                    ;;
            esac

            llvm_cmake_options=(
                -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING="${cmake_osx_deployment_target}"
                -DCMAKE_OSX_SYSROOT:PATH="$(xcrun --sdk ${xcrun_sdk_name} --show-sdk-path)"
                -DLLVM_ENABLE_LIBCXX:BOOL=TRUE
                -DCOMPILER_RT_ENABLE_IOS:BOOL=FALSE
                -DCOMPILER_RT_ENABLE_WATCHOS:BOOL=FALSE
                -DCOMPILER_RT_ENABLE_TVOS:BOOL=FALSE
                -DSANITIZER_MIN_OSX_VERSION="${cmake_osx_deployment_target}"
                -DLLVM_ENABLE_MODULES:BOOL="$(is_llvm_module_build_enabled)"
            )
            if [[ $(is_llvm_lto_enabled) == "TRUE" ]]; then
                if [[ $(cmake_needs_to_specify_standard_computed_defaults) == "TRUE" ]]; then
                    llvm_cmake_options+=(
                        "-DCMAKE_C_STANDARD_COMPUTED_DEFAULT=AppleClang"
                        "-DCMAKE_CXX_STANDARD_COMPUTED_DEFAULT=AppleClang"
                    )
                fi

                llvm_cmake_options+=(
                    "-DLLVM_PARALLEL_LINK_JOBS=${LLVM_NUM_PARALLEL_LTO_LINK_JOBS}"
                )
            fi

            if [[ $(is_swift_lto_enabled) == "TRUE" ]]; then
                if [[ $(cmake_needs_to_specify_standard_computed_defaults) = "TRUE" ]]; then
                    swift_cmake_options+=(
                        "-DCMAKE_C_STANDARD_COMPUTED_DEFAULT=AppleClang"
                        "-DCMAKE_CXX_STANDARD_COMPUTED_DEFAULT=AppleClang"
                    )
                fi

                llvm_cmake_options+=(
                    -DLLVM_ENABLE_MODULE_DEBUGGING:BOOL=NO
                )

                swift_cmake_options+=(
                    -DLLVM_ENABLE_MODULE_DEBUGGING:BOOL=NO
                    "-DSWIFT_PARALLEL_LINK_JOBS=${SWIFT_TOOLS_NUM_PARALLEL_LTO_LINK_JOBS}"
                )
            fi

            swift_cmake_options+=(
                -DSWIFT_DARWIN_DEPLOYMENT_VERSION_OSX="${DARWIN_DEPLOYMENT_VERSION_OSX}"
                -DSWIFT_DARWIN_DEPLOYMENT_VERSION_IOS="${DARWIN_DEPLOYMENT_VERSION_IOS}"
                -DSWIFT_DARWIN_DEPLOYMENT_VERSION_TVOS="${DARWIN_DEPLOYMENT_VERSION_TVOS}"
                -DSWIFT_DARWIN_DEPLOYMENT_VERSION_WATCHOS="${DARWIN_DEPLOYMENT_VERSION_WATCHOS}"
                -DLLVM_ENABLE_LIBCXX:BOOL=TRUE
            )
            ;;
        *)
            echo "Unknown host tools target: ${host}"
            exit 1
            ;;
    esac


    llvm_cmake_options+=(
        -DLLVM_TOOL_COMPILER_RT_BUILD:BOOL="$(false_true ${SKIP_BUILD_COMPILER_RT})"
        -DLLVM_BUILD_EXTERNAL_COMPILER_RT:BOOL="$(false_true ${SKIP_BUILD_COMPILER_RT})"
    )

    # If we are asked to not generate test targets for LLVM and or Swift,
    # disable as many LLVM tools as we can. This improves compile time when
    # compiling with LTO.
    #
    # *NOTE* Currently we do not support testing LLVM via build-script. But in a
    # future commit we will.
    #for arg in "$(compute_cmake_llvm_tool_disable_flags)"; do
    #    llvm_cmake_options+=( ${arg} )
    #done

    if [[ "${llvm_target_arch}" ]] ; then
        llvm_cmake_options+=(
            -DLLVM_TARGET_ARCH="${llvm_target_arch}"
        )
    fi

    # For cross-compilable hosts, we need to know the triple
    # and it must be the same for both LLVM and Swift

    if [[ "${SWIFT_HOST_TRIPLE}" ]] ; then
        llvm_cmake_options+=(
            -DLLVM_HOST_TRIPLE:STRING="${SWIFT_HOST_TRIPLE}"
        )
        swift_cmake_options+=(
            -DSWIFT_HOST_TRIPLE:STRING="${SWIFT_HOST_TRIPLE}"
        )
        lldb_cmake_options+=(
            -DLLVM_HOST_TRIPLE:STRING="${SWIFT_HOST_TRIPLE}"
        )
    fi
    swift_cmake_options+=(
        -DSWIFT_HOST_VARIANT="${SWIFT_HOST_VARIANT}"
        -DSWIFT_HOST_VARIANT_SDK="${SWIFT_HOST_VARIANT_SDK}"
        -DSWIFT_HOST_VARIANT_ARCH="${SWIFT_HOST_VARIANT_ARCH}"
    )

    if [[ "${LLVM_LIT_ARGS}" ]]; then
        llvm_cmake_options+=(
            -DLLVM_LIT_ARGS="${LLVM_LIT_ARGS}"
        )
        swift_cmake_options+=(
            -DLLVM_LIT_ARGS="${LLVM_LIT_ARGS}"
        )
    fi

    if [[ "${CLANG_PROFILE_INSTR_USE}" ]]; then
        llvm_cmake_options+=(
            -DLLVM_PROFDATA_FILE="${CLANG_PROFILE_INSTR_USE}"
        )
    fi

    swift_cmake_options+=(
        -DCOVERAGE_DB="${COVERAGE_DB}"
    )
}

function configure_default_options() {
    # Build a table of all of the known setting variables names.
    #
    # This is an optimization to do the argument to variable conversion (which is
    # slow) in a single pass.
    local all_settings=()
    for ((i = 0; i < ${#KNOWN_SETTINGS[@]}; i += 3)); do
        all_settings+=("${KNOWN_SETTINGS[i]}")
    done
    local known_setting_varnames=($(to_varname "${all_settings[*]}"))

    # Build up an "associative array" mapping setting names to variable names
    # (we use this for error checking to identify "known options", and as a fast
    # way to map the setting name to a variable name). See the code for scanning
    # command line arguments.
    #
    # This loop also sets (or unsets) each corresponding variable to its default
    # value.
    #
    # NOTE: If the Mac's bash were not stuck in the past, we could "declare -A"
    # an associative array, but instead we have to hack it by defining variables.
    for ((i = 0; i < ${#KNOWN_SETTINGS[@]}; i += 3)); do
        local setting="${KNOWN_SETTINGS[i]}"
        local default_value="${KNOWN_SETTINGS[$((i+1))]}"

        # Find the variable name in our lookup table.
        local varname="${known_setting_varnames[$((i/3))]}"

        # Establish the associative array mapping.
        eval "${setting//-/_}_VARNAME=${varname}"

        if [[ "${default_value}" ]] ; then
            # For an explanation of the backslash see http://stackoverflow.com/a/9715377
            eval ${varname}=$\default_value
        else
            unset ${varname}
        fi
    done
}
configure_default_options

COMMAND_NAME="$(basename "$0")"

# Print instructions for using this script to stdout
usage() {
    echo "Usage: ${COMMAND_NAME} [--help|-h] [ --SETTING=VALUE | --SETTING VALUE | --SETTING ]*"
    echo
    echo "  Available settings. Each setting corresponds to a variable,"
    echo "  obtained by upcasing its name, in this script.  A variable"
    echo "  with no default listed here will be unset in the script if"
    echo "  not explicitly specified.  A setting passed in the 3rd form"
    echo "  will set its corresponding variable to \"1\"."
    echo

    setting_list="
 | |Setting| Default|Description
 | |-------| -------|-----------
"

    for ((i = 0; i < ${#KNOWN_SETTINGS[@]}; i += 3)); do
        setting_list+="\
 | |--${KNOWN_SETTINGS[i]}| ${KNOWN_SETTINGS[$((i+1))]}|${KNOWN_SETTINGS[$((i+2))]}
"
    done
    echo "${setting_list}" | column -x -s'|' -t
    echo
    echo "Note: when using the form --SETTING VALUE, VALUE must not begin "
    echo "      with a hyphen."
    echo "Note: the \"--release\" option creates a pre-packaged combination"
    echo "      of settings used by the buildbot."
    echo
    echo "Cross-compiling Swift host tools"
    echo "  When building cross-compiled tools, it first builds for the native"
    echo "  build host machine. Then it proceeds to build the specified cross-compile"
    echo "  targets. It currently builds the requested variants of stdlib each"
    echo "  time around, so once for the native build, then again each time for"
    echo "  the cross-compile tool targets."
    echo
    echo "  When installing cross-compiled tools, it first installs each target"
    echo "  arch into a separate subdirectory under install-destdir, since you"
    echo "  can cross-compile for multiple targets at the same time. It then runs"
    echo "  recursive-lipo to produce fat binaries by merging the cross-compiled"
    echo "  targets, installing the merged result into the expected location of"
    echo "  install-destdir. After that, any remaining steps to extract dsyms and"
    echo "  create an installable package operates on install-destdir as normal."
}

# Scan all command-line arguments
while [[ "$1" ]] ; do
    case "$1" in
        -h | --help )
            usage
            exit
            ;;

        --* )
            dashless="${1:2}"

            # drop suffix beginning with the first "="
            setting="${dashless%%=*}"

            # compute the variable to set, using the cached map set up by
            # configure_default_options().
            varname_var="${setting//-/_}_VARNAME"
            varname=${!varname_var}

            # check to see if this is a known option
            if [[ "${varname}" = "" ]] ; then
                echo "error: unknown setting: ${setting}" 1>&2
                usage 1>&2
                exit 1
            fi

            # find the intended value
            if [[ "${dashless}" == *=* ]] ; then              # if there's an '=', the value
                value="${dashless#*=}"                        #   is everything after the first '='
            elif [[ "$2" ]] && [[ "${2:0:1}" != "-" ]] ; then # else if the next parameter exists
                value="$2"                                    #   but isn't an option, use that
                shift
            else                                              # otherwise, the value is 1
                value=1
            fi

            # For explanation of backslash see http://stackoverflow.com/a/9715377
            eval ${varname}=$\value
            ;;

        *)
            echo "Error: Invalid argument: $1" 1>&2
            usage 1>&2
            exit 1
    esac
    shift
done

# TODO: Rename this argument
LOCAL_HOST=$HOST_TARGET

# TODO: Remove this some time later.
if [[ "${USER_CONFIG_ARGS}" ]]; then
    echo "Error: --user-config-args is renamed to --extra-cmake-options." 1>&2
    exit 1
fi

if [[ "${CHECK_ARGS_ONLY}" ]]; then
    exit 0
fi

# FIXME: We currently do not support building compiler-rt with the
# Xcode generator.
if [[ "${CMAKE_GENERATOR}" == "Xcode" ]]; then
    SKIP_BUILD_COMPILER_RT=1
fi

# FIXME: We currently do not support cross-compiling swift with compiler-rt.
if [[ "${CROSS_COMPILE_HOSTS}" ]]; then
    SKIP_BUILD_COMPILER_RT=1
fi

# WORKSPACE, BUILD_DIR and INSTALLABLE_PACKAGE must be absolute paths
case "${WORKSPACE}" in
    /*) ;;
    *)
        echo "workspace must be an absolute path (was '${WORKSPACE}')"
        exit 1
        ;;
esac
case "${BUILD_DIR}" in
    /*) ;;
    "")
        echo "the --build-dir option is required"
        usage
        exit 1
        ;;
    *)
        echo "build-dir must be an absolute path (was '${BUILD_DIR}')"
        exit 1
        ;;
esac
case "${INSTALLABLE_PACKAGE}" in
    /*) ;;
    "") ;;
    *)
        echo "installable-package must be an absolute path (was '${INSTALLABLE_PACKAGE}')"
        exit 1
        ;;
esac

# WORKSPACE must exist
if [ ! -e "${WORKSPACE}" ] ; then
    echo "Workspace does not exist (tried ${WORKSPACE})"
    exit 1
fi

# FIXME: HOST_CC and CMAKE are set, and their presence is validated by,
#        utils/build-script. These checks are redundant, but must remain until
#        build-script-impl is merged completely with utils/build-script.
#        For additional information, see: https://bugs.swift.org/browse/SR-237
if [ -z "${HOST_CC}" ] ; then
    echo "Can't find clang.  Please install clang-3.5 or a later version."
    exit 1
fi
if [ -z "${CMAKE}" ] ; then
    echo "Environment variable CMAKE must be specified."
    exit 1
fi

function xcrun_find_tool() {
  xcrun --sdk macosx --toolchain "${DARWIN_XCRUN_TOOLCHAIN}" --find "$@"
}

function not() {
    if [[ ! "$1" ]] ; then
        echo 1
    fi
}

function join { 
    local IFS="$1"; shift; echo "$*"; 
}

function false_true() {
    if [[ $(true_false "$1") = "TRUE" ]]; then
        echo "FALSE"
    else
        echo "TRUE"
    fi
}

function cmake_version() {
    "${CMAKE}" --version | grep "cmake version" | cut -f 3 -d " "
}

function cmake_needs_to_specify_standard_computed_defaults() {
    if [[ $(cmake_version) = "3.4.0" ]]; then
        echo "TRUE"
    else
        echo "FALSE"
    fi
}

function copy_swift_stdlib_tool_substitute() {
    if [ ! -f "$1" ] ; then
        echo "--- Copy swift-stdlib-tool ---"
        call cp "${SWIFT_SOURCE_DIR}/utils/swift-stdlib-tool-substitute" "$1"
    fi
}

function make_relative_symlink() {
    local SOURCE=$1
    local TARGET=$2
    local TARGET_DIR=$(dirname $2)
    local RELATIVE_SOURCE=$(python -c "import os.path; print(os.path.relpath(\"${SOURCE}\", \"${TARGET_DIR}\"))")
    call ln -sf "${RELATIVE_SOURCE}" "${TARGET}"
}

# Sanitize the list of cross-compilation targets.
#
# In the Build/Host/Target paradigm:
# - "LOCAL_HOST" is Build (local machine running this script)
# - "CROSS_COMPILE_HOSTS" are the Hosts (implicitly includes LOCAL_HOST)
# - "STDLIB_DEPLOYMENT_TARGETS" are the Targets (for configuration)
# - "BUILD_STDLIB_DEPLOYMENT_TARGETS" are the Targets to build in this invocation

CROSS_COMPILE_HOSTS=($CROSS_COMPILE_HOSTS)
for t in "${CROSS_COMPILE_HOSTS[@]}"; do
    case ${t} in
        iphone* | appletv* | watch* | linux-armv6 | linux-armv7 )
            ;;
        *)
            echo "Unknown host to cross-compile for: ${t}"
            exit 1
            ;;
    esac
done

ALL_HOSTS=("${LOCAL_HOST}" "${CROSS_COMPILE_HOSTS[@]}")

function has_cross_compile_hosts() {
    if [[ ${#ALL_HOSTS[@]} -gt 1 ]]; then
        echo "1"
    fi
}

# We install in to host-specific directories when building more than one host.
# Other users will expect their products at INSTALL_DESTDIR.
function get_host_install_destdir() {
   local host="$1"

    if [[ $(has_cross_compile_hosts) ]]; then
        # If cross compiling tools, install into a host-specific subdirectory.
        if [[ $(should_include_host_in_lipo ${host}) ]]; then
            # If this is one of the hosts we should lipo, install in to a temporary subdirectory.
            local host_install_destdir="${BUILD_DIR}/intermediate-install/${host}"
        else
            local host_install_destdir="${INSTALL_DESTDIR}/${host}"
        fi
    else
        local host_install_destdir="${INSTALL_DESTDIR}"
    fi

    echo "${host_install_destdir}/" # Should always end in a '/'; it's a directory.
}

function splitSemicolonDelimitedInstallPrefixes() {
    local IFS=";"; CROSS_COMPILE_INSTALL_PREFIXES=($CROSS_COMPILE_INSTALL_PREFIXES)
}
splitSemicolonDelimitedInstallPrefixes

function get_host_install_prefix() {
    local host="$1"
   
    if [[ $(is_cross_tools_host ${host}) ]] && [[ ${#CROSS_COMPILE_INSTALL_PREFIXES[@]} -gt 0 ]]; then

        # Find the host's index in CROSS_COMPILE_HOSTS.
        for i in "${!CROSS_COMPILE_HOSTS[@]}"; do
           if [[ "${CROSS_COMPILE_HOSTS[$i]}" == "${host}" ]]; then
               local host_index=i
           fi
        done

        if [[ ${host_index} -lt ${#CROSS_COMPILE_INSTALL_PREFIXES[@]} ]]; then
            local host_install_prefix="${CROSS_COMPILE_INSTALL_PREFIXES[${host_index}]}"
        else
            # If there is no explicit install prefix for this host, use the last one
            # in the list.
            local host_install_prefix="${CROSS_COMPILE_INSTALL_PREFIXES[${#CROSS_COMPILE_INSTALL_PREFIXES[@]}-1]}"
        fi
    else
        local host_install_prefix="${INSTALL_PREFIX}"
    fi

    # Should always begin with a '/'; otherwise CMake will expand it as a relative path from the build folder.
    if [[ "${host_install_prefix:0:1}" != "/" ]]; then
        host_install_prefix="/${host_install_prefix}"
    fi

    echo "${host_install_prefix}/" # Should always end in a '/'; it's a directory.
}

function is_cross_tools_host() {
    local host="$1"
    for t in "${CROSS_COMPILE_HOSTS[@]}" ; do
        if [ "${host}" == "${t}" ] ; then
            echo 1
        fi
    done
}

# When building cross-compilers for these hosts,
# merge all of their contents together with lipo
function should_include_host_in_lipo() {
    local host="$1"
    if [[ $(has_cross_compile_hosts) ]] && [[ -z "${SKIP_MERGE_LIPO_CROSS_COMPILE_TOOLS}" ]]; then
        case ${host} in 
            iphone* | appletv* | watch* )
                echo 1
                ;;
        esac
    fi
}

function host_has_darwin_symbols() {
    local host="$1"
    case ${host} in 
        macosx* | iphone* | appletv* | watch* )
            echo 1
            ;;
    esac
}

function get_stdlib_targets_for_host() {

# FIXME: STDLIB_DEPLOYMENT_TARGETS argument assumed to apply when Host == Build
# Cross-compile Hosts are only built with their native standard libraries.
# To fix this, we would need to pass in a list of stdlib targets _per host_,
# and the SWIFT_SDKS parameters would need to be able to capture both the SDK 
# and architecture of each stdlib target -- currently it only captures the SDK.
#
# We turn these targets in to SWIFT_SDKS in `calculate_targets_for_host()`
    
    if [[ $(is_cross_tools_host $1) ]] ; then
        echo "$1"
    else
        echo "${STDLIB_DEPLOYMENT_TARGETS[@]}"
    fi
}

function should_build_stdlib_target() {
    local stdlib_target=$1
    local host=$2
    if [[ "${BUILD_STDLIB_DEPLOYMENT_TARGETS}" == "all" ]]; then
        echo 1
    else
        # Only build the stdlib targets in 'build-stdlib-deployment-targets'
        local build_list=($BUILD_STDLIB_DEPLOYMENT_TARGETS)
        for t in "${build_list[@]}"; do
            if [[ "${t}" == "${stdlib_target}" ]]; then
                echo 1
            fi
        done
        # As with 'stdlib-deployment-targets', 'build-stdlib-deployment-targets'
        # only applies to the LOCAL_HOST. For cross-tools hosts, always allow
        # their one-and-only stdlib-target to build.
        if [[ $(is_cross_tools_host ${host}) ]] && [[ "${stdlib_target}" == "${host}" ]]; then
            echo 1
        fi
    fi
}

#
# Calculate source directories for each product.
#
NINJA_SOURCE_DIR="${WORKSPACE}/ninja"
SWIFT_SOURCE_DIR="${WORKSPACE}/swift"
LLVM_SOURCE_DIR="${WORKSPACE}/llvm"
CMARK_SOURCE_DIR="${WORKSPACE}/cmark"
LLDB_SOURCE_DIR="${WORKSPACE}/lldb"
LLBUILD_SOURCE_DIR="${WORKSPACE}/llbuild"
SWIFTPM_SOURCE_DIR="${WORKSPACE}/swiftpm"
XCTEST_SOURCE_DIR="${WORKSPACE}/swift-corelibs-xctest"
FOUNDATION_SOURCE_DIR="${WORKSPACE}/swift-corelibs-foundation"
LIBDISPATCH_SOURCE_DIR="${WORKSPACE}/swift-corelibs-libdispatch"
PLAYGROUNDLOGGER_SOURCE_DIR="${WORKSPACE}/swift-xcode-playground-support/PlaygroundLogger"
PLAYGROUNDSUPPORT_SOURCE_DIR="${WORKSPACE}/swift-xcode-playground-support/PlaygroundSupport"

if [[ ! -d ${CMARK_SOURCE_DIR} ]]; then
    echo "Couldn't find cmark source directory."
    exit 1
fi

if [[ ! "${SKIP_BUILD_LLBUILD}" && ! -d ${LLBUILD_SOURCE_DIR} ]]; then
    echo "Couldn't find llbuild source directory."
    exit 1
fi

if [[ ! "${SKIP_BUILD_SWIFTPM}" && ! -d ${SWIFTPM_SOURCE_DIR} ]]; then
    echo "Couldn't find swiftpm source directory."
    exit 1
fi

if [[ ! "${SKIP_BUILD_XCTEST}" && ! -d ${XCTEST_SOURCE_DIR} ]]; then
    echo "Couldn't find XCTest source directory."
    exit 1
fi

if [[ ! "${SKIP_BUILD_FOUNDATION}" && ! -d ${FOUNDATION_SOURCE_DIR} ]]; then
    echo "Couldn't find Foundation source directory."
    exit 1
fi

if [[ ! "${SKIP_BUILD_LIBDISPATCH}" && ! -d ${LIBDISPATCH_SOURCE_DIR} ]]; then
    echo "Couldn't find libdispatch source directory."
    exit 1
fi

if [[ ! "${SKIP_BUILD_PLAYGROUNDLOGGER}" && ! -d ${PLAYGROUNDLOGGER_SOURCE_DIR} ]]; then
    echo "Couldn't find PlaygroundLogger source directory."
    exit 1
fi

if [[ ! "${SKIP_BUILD_PLAYGROUNDSUPPORT}" && ! -d ${PLAYGROUNDSUPPORT_SOURCE_DIR} ]]; then
    echo "Couldn't find PlaygroundSupport source directory."
    exit 1
fi

# Symlink clang into the llvm tree.
CLANG_SOURCE_DIR="${LLVM_SOURCE_DIR}/tools/clang"
if [ ! -e "${WORKSPACE}/clang" ] ; then
    # If llvm/tools/clang is already a directory, use that and skip the symlink.
    if [ ! -d "${CLANG_SOURCE_DIR}" ] ; then
        echo "Can't find source directory for clang (tried ${WORKSPACE}/clang and ${CLANG_SOURCE_DIR})"
        exit 1
    fi
fi
if [ ! -d "${CLANG_SOURCE_DIR}" ] ; then
    make_relative_symlink "${WORKSPACE}/clang" "${CLANG_SOURCE_DIR}"
fi

# Symlink compiler-rt into the llvm tree, if it exists.
COMPILER_RT_SOURCE_DIR="${LLVM_SOURCE_DIR}/projects/compiler-rt"
if [ -e "${WORKSPACE}/compiler-rt" ] ; then
    if [ ! -d "${COMPILER_RT_SOURCE_DIR}" ] ; then
        make_relative_symlink "${WORKSPACE}/compiler-rt" "${COMPILER_RT_SOURCE_DIR}"
    fi
fi

PRODUCTS=(cmark llvm swift)
if [[ ! "${SKIP_BUILD_LLDB}" ]] ; then
     PRODUCTS=("${PRODUCTS[@]}" lldb)
fi
if [[ ! "${SKIP_BUILD_LLBUILD}" ]] ; then
     PRODUCTS=("${PRODUCTS[@]}" llbuild)
fi
if [[ ! "${SKIP_BUILD_LIBDISPATCH}" ]] ; then
     PRODUCTS=("${PRODUCTS[@]}" libdispatch)
fi
# SwiftPM and XCTest are dependent on Foundation, so Foundation must be
# added to the list of build products first.
if [[ ! "${SKIP_BUILD_FOUNDATION}" ]] ; then
     PRODUCTS=("${PRODUCTS[@]}" foundation)
fi
if [[ ! "${SKIP_BUILD_PLAYGROUNDLOGGER}" ]] ; then
     PRODUCTS=("${PRODUCTS[@]}" playgroundlogger)
fi
if [[ ! "${SKIP_BUILD_PLAYGROUNDSUPPORT}" ]] ; then
     PRODUCTS=("${PRODUCTS[@]}" playgroundsupport)
fi
# SwiftPM is dependent on XCTest, so XCTest must be added to the list of
# build products first.
if [[ ! "${SKIP_BUILD_XCTEST}" ]] ; then
     PRODUCTS=("${PRODUCTS[@]}" xctest)
fi
if [[ ! "${SKIP_BUILD_SWIFTPM}" ]] ; then
     PRODUCTS=("${PRODUCTS[@]}" swiftpm)
fi

# Checks if a given product is enabled (i.e. part of $PRODUCTS array)
function contains_product() {
  local current_product
  for current_product in "${PRODUCTS[@]}"; do
    if [[ "$current_product" == "$1" ]]; then
      return 0
    fi
  done
  return 1
}


# get_host_specific_variable(host, name)
#
# Get the value of a host-specific variable expected to have been passed by the
# `build-script`.
#
# This is a total hack, and is part of the SR-237 migration.
function get_host_specific_variable() {
    local host="$1"
    local name="$2"
    local envvar_name="HOST_VARIABLE_${host//-/_}__${name}"
    echo "${!envvar_name}"
}

function calculate_targets_for_host() {
    local host=$1
    
    SWIFT_STDLIB_TARGETS=()
    SWIFT_SDKS=()
    SWIFT_BENCHMARK_TARGETS=()
    SWIFT_RUN_BENCHMARK_TARGETS=()
    SWIFT_TEST_TARGETS=()

    # Get the list of Target platforms for the Host
    local stdlib_targets=($(get_stdlib_targets_for_host ${host}))

    for stdlib_deployment_target in "${stdlib_targets[@]}"; do
        local swift_sdk=
        local is_in_build_list=$(should_build_stdlib_target ${stdlib_deployment_target} ${host})
        local build_for_this_target=1
        local test_this_target=1
        local test_host_only=
        local build_benchmark_this_target=
        local test_benchmark_this_target=

        case ${stdlib_deployment_target} in
            linux-*)
                swift_sdk="LINUX"
                build_for_this_target=$(not ${SKIP_BUILD_LINUX})
                test_this_target=$(not ${SKIP_TEST_LINUX})
                ;;
            freebsd-*)
                swift_sdk="FREEBSD"
                build_for_this_target=$(not ${SKIP_BUILD_FREEBSD})
                test_this_target=$(not ${SKIP_TEST_FREEBSD})
                ;;
            cygwin-*)
                swift_sdk="CYGWIN"
                build_for_this_target=$(not ${SKIP_BUILD_CYGWIN})
                test_this_target=$(not ${SKIP_TEST_CYGWIN})
                ;;
            macosx-*)
                swift_sdk="OSX"
                build_for_this_target=$(not ${SKIP_BUILD_OSX})
                test_this_target=$(not ${SKIP_TEST_OSX})
                build_benchmark_this_target=$(not ${SKIP_BUILD_OSX})
                test_benchmark_this_target=$(not ${SKIP_BUILD_OSX})
                ;;
            iphoneos-*)
                swift_sdk="IOS"
                build_for_this_target=$(not ${SKIP_BUILD_IOS_DEVICE})
                if [[ ! "${SKIP_TEST_IOS_HOST}" ]] ; then
                    test_host_only=1
                else
                    test_this_target=
                fi
                build_benchmark_this_target=$(not ${SKIP_BUILD_IOS_DEVICE})

                # Never build iOS armv7s benchmarks.
                if [[ "${stdlib_deployment_target}" == "iphoneos-armv7s" ]]; then
                    build_benchmark_this_target=
                fi
                ;;
            iphonesimulator-*)
                swift_sdk="IOS_SIMULATOR"
                build_for_this_target=$(not ${SKIP_BUILD_IOS_SIMULATOR})
                test_this_target=$(not ${SKIP_TEST_IOS_SIMULATOR})
                ;;
            appletvos-*)
                swift_sdk="TVOS"
                build_for_this_target=$(not ${SKIP_BUILD_TVOS_DEVICE})
                if [[ ! "${SKIP_TEST_TVOS_HOST}" ]] ; then
                    test_host_only=1
                else
                    test_this_target=
                fi
                build_benchmark_this_target=$(not ${SKIP_BUILD_TVOS_DEVICE})
                ;;
            appletvsimulator-*)
                swift_sdk="TVOS_SIMULATOR"
                build_for_this_target=$(not ${SKIP_BUILD_TVOS_SIMULATOR})
                test_this_target=$(not ${SKIP_TEST_TVOS_SIMULATOR})
                ;;
            watchos-*)
                swift_sdk="WATCHOS"
                build_for_this_target=$(not ${SKIP_BUILD_WATCHOS_DEVICE})
                if [[ ! "${SKIP_TEST_WATCHOS_HOST}" ]] ; then
                    test_host_only=1
                else
                    test_this_target=
                fi
                build_benchmark_this_target=$(not ${SKIP_BUILD_WATCHOS_DEVICE})
                ;;
            watchsimulator-*)
                swift_sdk="WATCHOS_SIMULATOR"
                build_for_this_target=$(not ${SKIP_BUILD_WATCHOS_SIMULATOR})
                test_this_target=$(not ${SKIP_TEST_WATCHOS_SIMULATOR})
                ;;
            android-*)
                swift_sdk="ANDROID"
                build_for_this_target=$(not ${SKIP_BUILD_ANDROID})
                test_this_target=$(not ${SKIP_TEST_ANDROID_HOST})
                ;;
            *)
                echo "Unknown compiler deployment target: ${stdlib_deployment_target}"
                exit 1
                ;;
        esac

        SWIFT_SDKS+=("${swift_sdk}")

        if [[ "${build_for_this_target}" ]] && [[ "${is_in_build_list}" ]]; then

            if [[ "${BUILD_SWIFT_STDLIB_UNITTEST_EXTRA}" == "1" ]] ; then
                SWIFT_STDLIB_TARGETS+=("swift-stdlib-${stdlib_deployment_target}")
            else
                if [[ "${VALIDATION_TEST}" == "1" || "${LONG_TEST}" == "1" ]] ; then
                    SWIFT_STDLIB_TARGETS+=("swift-stdlib-${stdlib_deployment_target}")
                else
                    SWIFT_STDLIB_TARGETS+=("swift-test-stdlib-${stdlib_deployment_target}")
                fi
            fi
        fi
        if [[ "${build_benchmark_this_target}" ]] && [[ "${is_in_build_list}" ]]; then
            SWIFT_BENCHMARK_TARGETS+=("swift-benchmark-${stdlib_deployment_target}")
            if [[ $(not ${SKIP_TEST_BENCHMARK}) ]] ; then
              SWIFT_RUN_BENCHMARK_TARGETS+=("check-swift-benchmark-${stdlib_deployment_target}")
            fi
        fi
        if [[ "${test_this_target}" ]] && [[ "${is_in_build_list}" ]]; then
            test_target_suffix=""
            if [[ -n "${test_host_only}" ]] ; then
                test_target_suffix="-non-executable"
            fi

            test_subset_target_suffix=""
            if [[ "${VALIDATION_TEST}" == "1" ]] ; then
                if [[ "${LONG_TEST}" == "1" ]] ; then
                    test_subset_target_suffix="-all"
                else
                    test_subset_target_suffix="-validation"
                fi
            else
                if [[ "${LONG_TEST}" == "1" ]] ; then
                    test_subset_target_suffix="-only_long"
                fi
            fi
            SWIFT_TEST_TARGETS+=("check-swift${test_subset_target_suffix}${test_target_suffix}-${stdlib_deployment_target}")
            if [[ $(not ${SKIP_TEST_OPTIMIZED}) && ! -n "${test_host_only}" ]] ; then
                SWIFT_TEST_TARGETS+=("check-swift${test_subset_target_suffix}-optimize-${stdlib_deployment_target}")
            fi
        fi
    done

    # Filter duplicate SWIFT_SDKs
    # We will get them if building for multiple architecture variants
    SWIFT_SDKS=($(echo "${SWIFT_SDKS[@]}" | tr " " "\n" | sort -u | tr "\n" " "))

    # Get the values passed by `build-script`.
    LEGACY_SWIFT_STDLIB_TARGETS=(${SWIFT_STDLIB_TARGETS[@]})
    LEGACY_SWIFT_SDKS=(${SWIFT_SDKS[@]})
    LEGACY_SWIFT_BENCHMARK_TARGETS=(${SWIFT_BENCHMARK_TARGETS[@]})
    LEGACY_SWIFT_RUN_BENCHMARK_TARGETS=(${SWIFT_RUN_BENCHMARK_TARGETS[@]})
    LEGACY_SWIFT_TEST_TARGETS=(${SWIFT_TEST_TARGETS[@]})
    SWIFT_STDLIB_TARGETS=($(get_host_specific_variable ${host} SWIFT_STDLIB_TARGETS))
    SWIFT_SDKS=($(get_host_specific_variable ${host} SWIFT_SDKS))
    SWIFT_BENCHMARK_TARGETS=($(get_host_specific_variable ${host} SWIFT_BENCHMARK_TARGETS))
    SWIFT_RUN_BENCHMARK_TARGETS=($(get_host_specific_variable ${host} SWIFT_RUN_BENCHMARK_TARGETS))
    SWIFT_TEST_TARGETS=($(get_host_specific_variable ${host} SWIFT_TEST_TARGETS))

    # Validate the parameters match.
    if [[ "${SWIFT_STDLIB_TARGETS[*]}" != "${LEGACY_SWIFT_STDLIB_TARGETS[*]}" ]]; then
        printf "error: invalid build-script refactor for 'SWIFT_STDLIB_TARGETS': '%s' vs '%s'\n" "${SWIFT_STDLIB_TARGETS[*]}" "${LEGACY_SWIFT_STDLIB_TARGETS[*]}"
        exit 1
    fi
    if [[ "${SWIFT_SDKS[*]}" != "${LEGACY_SWIFT_SDKS[*]}" ]]; then
        printf "error: invalid build-script for 'SWIFT_SDKS' refactor: '%s' vs '%s'\n" "${SWIFT_SDKS[*]}" "${LEGACY_SWIFT_SDKS[*]}"
        exit 1
    fi
    if [[ "${SWIFT_BENCHMARK_TARGETS[*]}" != "${LEGACY_SWIFT_BENCHMARK_TARGETS[*]}" ]]; then
        printf "error: invalid build-script refactor for 'SWIFT_BENCHMARK_TARGETS': '%s' vs '%s'\n" "${SWIFT_BENCHMARK_TARGETS[*]}" "${LEGACY_SWIFT_BENCHMARK_TARGETS[*]}"
        exit 1
    fi
    if [[ "${SWIFT_RUN_BENCHMARK_TARGETS[*]}" != "${LEGACY_SWIFT_RUN_BENCHMARK_TARGETS[*]}" ]]; then
        printf "error: invalid build-script refactor for 'SWIFT_RUN_BENCHMARK_TARGETS': '%s' vs '%s'\n" "${SWIFT_RUN_BENCHMARK_TARGETS[*]}" "${LEGACY_SWIFT_RUN_BENCHMARK_TARGETS[*]}"
        exit 1
    fi
    if [[ "${SWIFT_TEST_TARGETS[*]}" != "${LEGACY_SWIFT_TEST_TARGETS[*]}" ]]; then
        printf "error: invalid build-script refactor for 'SWIFT_TEST_TARGETS': '%s' vs '%s'\n" "${SWIFT_TEST_TARGETS[*]}" "${LEGACY_SWIFT_TEST_TARGETS[*]}"
        exit 1
    fi
}


COMMON_C_FLAGS=""

# Convert to an array.
eval COMMON_CMAKE_OPTIONS=(${COMMON_CMAKE_OPTIONS})
eval EXTRA_CMAKE_OPTIONS=(${EXTRA_CMAKE_OPTIONS})
eval BUILD_ARGS=(${BUILD_ARGS})

if [[ -n "${DISTCC}" ]]; then
    if [[ "$(uname -s)" == "Darwin" ]] ; then
        # These are normally deduced by CMake, but when the compiler is set to
        # distcc which is installed elsewhere, we need to set them explicitly.
        COMMON_CMAKE_OPTIONS=(
            "${COMMON_CMAKE_OPTIONS[@]}" "-DCMAKE_AR=$(xcrun_find_tool ar)"
            "-DCMAKE_LINKER=$(xcrun_find_tool ld)"
            "-DCMAKE_NM=$(xcrun_find_tool nm)"
            "-DCMAKE_OBJDUMP=$(xcrun_find_tool objdump)"
            "-DCMAKE_RANLIB=$(xcrun_find_tool ranlib)"
            "-DCMAKE_STRIP=$(xcrun_find_tool strip)"
        )
    fi
fi

eval CMAKE_BUILD=("${DISTCC_PUMP}" "${CMAKE}" "--build")


if [[ "${CMAKE_GENERATOR}" == "Xcode" ]]; then
    BUILD_TARGET_FLAG="-target"
fi

function build_directory() {
    host=$1
    product=$2
    echo "${BUILD_DIR}/${product}-${host}"
}

function build_directory_bin() {
    host=$1
    product=$2
    root="$(build_directory ${host} ${product})"
    if [[ "${CMAKE_GENERATOR}" == "Xcode" ]] ; then
        case ${product} in
            cmark)
                echo "${root}/${CMARK_BUILD_TYPE}/bin"
                ;;
            llvm)
                echo "${root}/${LLVM_BUILD_TYPE}/bin"
                ;;
            swift)
                echo "${root}/${SWIFT_BUILD_TYPE}/bin"
                ;;
            lldb)
                ;;
            llbuild)
                echo "${root}/${LLBUILD_BUILD_TYPE}/bin"
                ;;
            swiftpm)
                echo "${root}/${SWIFTPM_BUILD_TYPE}/bin"
                ;;
            xctest)
                echo "${root}/${XCTEST_BUILD_TYPE}/bin"
                ;;
            foundation)
                echo "${root}/${FOUNDATION_BUILD_TYPE}/bin"
                ;;
            libdispatch)
                echo "${root}/${LIBDISPATCH_BUILD_TYPE}/bin"
                ;;
            playgroundlogger)
                # FIXME: var name for build type
                echo "${root}/${PLAYGROUNDLOGGER_BUILD_TYPE}/bin"
                ;;
            playgroundsupport)
                echo "${root}/${PLAYGROUNDSUPPORT_BUILD_TYPE}/bin"
                ;;
            *)
                echo "error: unknown product: ${product}"
                exit 1
                ;;
        esac
    else
        echo "${root}/bin"
    fi
}

function is_cmake_release_build_type() {
    if [[ "$1" == "Release" || "$1" == "RelWithDebInfo" ]] ; then
        echo 1
    fi
}

function is_cmake_debuginfo_build_type() {
    if [[ "$1" == "Debug" || "$1" == "RelWithDebInfo" ]] ; then
        echo 1
    fi
}

function common_cross_c_flags() {
    echo -n "${COMMON_C_FLAGS}"

    case $1 in
        iphonesimulator-i386)
            echo "-arch i386 -mios-simulator-version-min=${DARWIN_DEPLOYMENT_VERSION_IOS}"
            ;;
        iphonesimulator-x86_64)
            echo "-arch x86_64 -mios-simulator-version-min=${DARWIN_DEPLOYMENT_VERSION_IOS}"
            ;;
        iphoneos-armv7)
            echo "-arch armv7 -miphoneos-version-min=${DARWIN_DEPLOYMENT_VERSION_IOS}"
            ;;
        iphoneos-armv7s)
            echo "-arch armv7s -miphoneos-version-min=${DARWIN_DEPLOYMENT_VERSION_IOS}"
            ;;
        iphoneos-arm64)
            echo "-arch arm64 -miphoneos-version-min=${DARWIN_DEPLOYMENT_VERSION_IOS}"
            ;;
        appletvsimulator-x86_64)
            echo "-arch x86_64 -mtvos-simulator-version-min=${DARWIN_DEPLOYMENT_VERSION_TVOS}"
            ;;
        appletvos-arm64)
            echo "-arch arm64 -mtvos-version-min=${DARWIN_DEPLOYMENT_VERSION_TVOS}"
            ;;
        watchsimulator-i386)
            echo "-arch i386 -mwatchos-simulator-version-min=${DARWIN_DEPLOYMENT_VERSION_WATCHOS}"
            ;;
        watchos-armv7k)
            echo "-arch armv7k -mwatchos-version-min=${DARWIN_DEPLOYMENT_VERSION_WATCHOS}"
            ;;
        android-armv7)
            echo "-arch armv7"
            ;;
    esac
}

function llvm_c_flags() {
    echo -n " $(common_cross_c_flags $1)"
    if [[ $(is_cmake_release_build_type "${LLVM_BUILD_TYPE}") ]] ; then
        echo -n " -fno-stack-protector"
    fi
    if [[ $(is_cmake_debuginfo_build_type "${LLVM_BUILD_TYPE}") ]] ; then
        if [[ $(is_llvm_lto_enabled) == "TRUE" ]] ; then
            echo -n " -gline-tables-only"
        else
            echo -n " -g"
        fi
    fi
}

function cmark_c_flags() {
    echo -n " $(common_cross_c_flags $1)"
    if [[ $(is_cmake_release_build_type "${CMARK_BUILD_TYPE}") ]] ; then
        echo -n " -fno-stack-protector"
    fi
}

function swift_c_flags() {
    # Don't pass common_cross_c_flags to Swift because CMake code in the Swift
    # project is itself aware of cross-compilation for the host tools and
    # standard library.
    echo -n "${COMMON_C_FLAGS}"
    if [[ $(is_cmake_release_build_type "${SWIFT_BUILD_TYPE}") ]] ; then
        echo -n " -fno-stack-protector"
    fi
}

function cmake_config_opt() {
    product=$1
    if [[ "${CMAKE_GENERATOR}" == "Xcode" ]] ; then
        # CMake automatically adds --target ALL_BUILD if we don't pass this.
        echo "--target ZERO_CHECK "
        case ${product} in
            cmark)
                echo "--config ${CMARK_BUILD_TYPE}"
                ;;
            llvm)
                echo "--config ${LLVM_BUILD_TYPE}"
                ;;
            swift)
                echo "--config ${SWIFT_BUILD_TYPE}"
                ;;
            lldb)
                ;;
            llbuild)
                echo "--config ${LLBUILD_BUILD_TYPE}"
                ;;
            swiftpm)
                echo "--config ${SWIFTPM_BUILD_TYPE}"
                ;;
            xctest)
                echo "--config ${XCTEST_BUILD_TYPE}"
                ;;
            foundation)
                echo "--config ${FOUNDATION_BUILD_TYPE}"
                ;;            
            libdispatch)
                ;;
            playgroundlogger)
                # FIXME: var name
                echo "--config ${PLAYGROUNDLOGGER_BUILD_TYPE}"
                ;;
            playgroundsupport)
                echo "--config ${PLAYGROUNDSUPPORT_BUILD_TYPE}"
                ;;
            *)
                echo "error: unknown product: ${product}"
                exit 1
                ;;
        esac
    fi
}

function set_swiftpm_bootstrap_command() {
    SWIFTC_BIN="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc"
    LLBUILD_BIN="$(build_directory_bin ${LOCAL_HOST} llbuild)/swift-build-tool"
    if [[ ! "${SKIP_BUILD_FOUNDATION}" ]] ; then
        FOUNDATION_BUILD_DIR=$(build_directory ${host} foundation)
        if [[ ! "${SKIP_BUILD_LIBDISPATCH}" ]] ; then
            LIBDISPATCH_BUILD_DIR="$(build_directory ${host} libdispatch)"
            LIBDISPATCH_BUILD_ARGS="--libdispatch-source-dir=${LIBDISPATCH_SOURCE_DIR} --libdispatch-build-dir=${LIBDISPATCH_BUILD_DIR}"
        fi
        if [[ ! "${SKIP_BUILD_XCTEST}" ]] ; then
            XCTEST_BUILD_DIR=$(build_directory ${host} xctest)
        fi
    fi
    if [ "${SKIP_BUILD_LLBUILD}" ]; then
        echo "Error: Cannot build swiftpm without llbuild (swift-build-tool)."
        exit 1
    fi
    swiftpm_bootstrap_command=("${SWIFTPM_SOURCE_DIR}/Utilities/bootstrap" "${swiftpm_bootstrap_options[@]}")
    if [[ "${VERBOSE_BUILD}" ]] ; then
        swiftpm_bootstrap_command+=(-v)
    fi
    # FIXME CROSSCOMPILING:
    # SwiftPM needs to be told about the target, sysroot and linker to use
    # when cross-compiling
    swiftpm_bootstrap_command+=(
        --swiftc="${SWIFTC_BIN}"
        --sbt="${LLBUILD_BIN}"
        --build="${build_dir}")
    if [[ ! "${SKIP_BUILD_FOUNDATION}" ]] ; then
        swiftpm_bootstrap_command+=(
            --foundation="${FOUNDATION_BUILD_DIR}/Foundation")
        if [[ ! "${SKIP_BUILD_LIBDISPATCH}" ]] ; then
            swiftpm_bootstrap_command+=(
                $LIBDISPATCH_BUILD_ARGS)
        fi
        if [[ ! "${SKIP_BUILD_XCTEST}" ]] ; then
            swiftpm_bootstrap_command+=(
                --xctest="${XCTEST_BUILD_DIR}")
        fi
    fi
}

# Construct the appropriate options to pass to an Xcode
# build of any LLDB target.
function set_lldb_xcodebuild_options() {
    llvm_build_dir=$(build_directory ${host} llvm)
    cmark_build_dir=$(build_directory ${host} cmark)
    lldb_build_dir=$(build_directory ${host} lldb)
    swift_build_dir=$(build_directory ${host} swift)

    lldb_xcodebuild_options=(
        LLDB_PATH_TO_LLVM_SOURCE="${LLVM_SOURCE_DIR}"
        LLDB_PATH_TO_CLANG_SOURCE="${CLANG_SOURCE_DIR}"
        LLDB_PATH_TO_SWIFT_SOURCE="${SWIFT_SOURCE_DIR}"
        LLDB_PATH_TO_LLVM_BUILD="${llvm_build_dir}"
        LLDB_PATH_TO_CLANG_BUILD="${llvm_build_dir}"
        LLDB_PATH_TO_SWIFT_BUILD="${swift_build_dir}"
        LLDB_PATH_TO_CMARK_BUILD="${cmark_build_dir}"
        LLDB_IS_BUILDBOT_BUILD="${LLDB_IS_BUILDBOT_BUILD}"
        LLDB_BUILD_DATE="\"${LLDB_BUILD_DATE}\""
        SYMROOT="${lldb_build_dir}"
        OBJROOT="${lldb_build_dir}"
        ${LLDB_EXTRA_XCODEBUILD_ARGS}
    )
    if [[ "${LLDB_NO_DEBUGSERVER}" ]] ; then
        lldb_xcodebuild_options=(
            "${lldb_xcodebuild_options[@]}"
            DEBUGSERVER_DISABLE_CODESIGN="1"
            DEBUGSERVER_DELETE_AFTER_BUILD="1"
        )
    fi
    if [[ "${LLDB_USE_SYSTEM_DEBUGSERVER}" ]] ; then
        lldb_xcodebuild_options=(
            "${lldb_xcodebuild_options[@]}"
            DEBUGSERVER_USE_FROM_SYSTEM="1"
        )
    fi
}

#
# Configure and build each product
#
# Start with native deployment targets because the resulting tools are used during cross-compilation.


for host in "${ALL_HOSTS[@]}"; do
    # Skip this pass when the only action to execute can't match.
    if ! [[ $(should_execute_host_actions_for_phase ${host} build) ]]; then
        continue
    fi

    calculate_targets_for_host $host

    set_build_options_for_host $host

    # Don't echo anything if only executing an individual action.
    if [[ "${ONLY_EXECUTE}" = "all" ]]; then
        echo "Building the standard library for: ${SWIFT_STDLIB_TARGETS[@]}"
        if [[ "${SWIFT_TEST_TARGETS[@]}" ]] && ! [[ "${SKIP_TEST_SWIFT}" ]]; then
            echo "Running Swift tests for: ${SWIFT_TEST_TARGETS[@]}"
        fi
        if ! [[ "${SKIP_TEST_BENCHMARKS}" ]] &&
                [[ "${SWIFT_RUN_BENCHMARK_TARGETS[@]}" ]] &&
                ! [[ "${SKIP_TEST_BENCHMARK}" ]]; then
            echo "Running Swift benchmarks for: ${SWIFT_RUN_BENCHMARK_TARGETS[@]}"
        fi
    fi

    common_cmake_options_host=("${COMMON_CMAKE_OPTIONS[@]}")

    if [[ $(is_cross_tools_host ${host}) ]] ; then

        if [[ "${CROSS_COMPILE_WITH_HOST_TOOLS}" ]]; then
            # Optionally use the freshly-built host copy of clang to build
            # for foreign hosts.
            common_cmake_options_host+=(
                -DCMAKE_C_COMPILER="$(build_directory ${LOCAL_HOST} llvm)/bin/clang"
                -DCMAKE_CXX_COMPILER="$(build_directory ${LOCAL_HOST} llvm)/bin/clang++"
            )
        fi

        # CMake can't relink when using Ninja, but that's okay -
        # we don't need a build-local rpath because we can't run cross-compiled products
        if [[ "${CMAKE_GENERATOR}" == "Ninja" ]]; then
            common_cmake_options_host+=(
                -DCMAKE_BUILD_WITH_INSTALL_RPATH="1"
            )
        fi
    fi

    llvm_cmake_options=(
        "${llvm_cmake_options[@]}"
        -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})"
        -DINTERNAL_INSTALL_PREFIX="local"
    )

    if [[ "${DARWIN_TOOLCHAIN_VERSION}" ]] ; then
        swift_cmake_options=(
            "${swift_cmake_options[@]}"
            -DDARWIN_TOOLCHAIN_VERSION="${DARWIN_TOOLCHAIN_VERSION}"
        )
    fi

    if [[ "${ENABLE_ASAN}" || "$(uname -s)" == "Linux" ]] ; then
        swift_cmake_options=(
            "${swift_cmake_options[@]}"
            -DSWIFT_SOURCEKIT_USE_INPROC_LIBRARY:BOOL=TRUE
        )
    fi

    if [[ "${DARWIN_CRASH_REPORTER_CLIENT}" ]] ; then
        swift_cmake_options=(
            "${swift_cmake_options[@]}"
            -DSWIFT_RUNTIME_CRASH_REPORTER_CLIENT:BOOL=TRUE
        )
    fi

    swift_cmake_options=(
        "${swift_cmake_options[@]}"
        -DSWIFT_DARWIN_XCRUN_TOOLCHAIN:STRING="${DARWIN_XCRUN_TOOLCHAIN}"
    )

    if [[ "${DARWIN_STDLIB_INSTALL_NAME_DIR}" ]] ; then
        swift_cmake_options=(
            "${swift_cmake_options[@]}"
            -DSWIFT_DARWIN_STDLIB_INSTALL_NAME_DIR:STRING="${DARWIN_STDLIB_INSTALL_NAME_DIR}"
        )
    fi

    if [[ "${EXTRA_SWIFT_ARGS}" ]] ; then
        swift_cmake_options=(
            "${swift_cmake_options[@]}"
            -DSWIFT_EXPERIMENTAL_EXTRA_REGEXP_FLAGS="${EXTRA_SWIFT_ARGS}"
        )
    fi

    swift_cmake_options=(
        "${swift_cmake_options[@]}"
        -DSWIFT_AST_VERIFIER:BOOL=$(true_false "${SWIFT_ENABLE_AST_VERIFIER}")
        -DSWIFT_SIL_VERIFY_ALL:BOOL=$(true_false "${SIL_VERIFY_ALL}")
        -DSWIFT_RUNTIME_ENABLE_LEAK_CHECKER:BOOL=$(true_false "${SWIFT_RUNTIME_ENABLE_LEAK_CHECKER}")
    )

    for product in "${PRODUCTS[@]}"; do
        # Check if we should perform this action.
        if ! [[ $(should_execute_action "${host}-${product}-build") ]]; then
            continue
        fi

        unset skip_build
        source_dir_var="$(toupper ${product})_SOURCE_DIR"
        source_dir=${!source_dir_var}
        build_dir=$(build_directory ${host} ${product})
        build_targets=(all)

        cmake_options=("${common_cmake_options_host[@]}")

        # Add in gold linker support if requested.
        if [[ "${USE_GOLD_LINKER}" ]]; then
            echo "${product}: using gold linker"
            if [[ "${product}" != "swift" ]]; then
                # All other projects override the linker flags to add in
                # gold linker support.
                cmake_options=(
                    "${cmake_options[@]}"
                    -DCMAKE_EXE_LINKER_FLAGS:STRING="-fuse-ld=gold"
                    -DCMAKE_SHARED_LINKER_FLAGS:STRING="-fuse-ld=gold"
                )
            fi
        else
            echo "${product}: using standard linker"
        fi

        llvm_build_dir=$(build_directory ${host} llvm)
        module_cache="${build_dir}/module-cache"

        # Add any specific cmake options specified by build-script
        product_cmake_options_name=$(to_varname "${product}")_CMAKE_OPTIONS
        product_cmake_options=(${!product_cmake_options_name}) # convert to array
        cmake_options+=("${product_cmake_options[@]}")

        case ${product} in
            cmark)
                cmake_options=(
                  "${cmake_options[@]}"
                  -DCMAKE_BUILD_TYPE:STRING="${CMARK_BUILD_TYPE}"
                  "${cmark_cmake_options[@]}"
                )
                skip_build=${SKIP_BUILD_CMARK}
                build_targets=(all)
                ;;

            llvm)
                if [ "${BUILD_LLVM}" == "0" ] ; then
                    build_targets=(clean)
                fi
                if [ "${SKIP_BUILD_LLVM}" ] ; then
                    # We can't skip the build completely because the standalone
                    # build of Swift depend on these.
                    build_targets=(llvm-tblgen clang-headers)
                fi

                # Note: we set the variable:
                #
                # LLVM_TOOL_SWIFT_BUILD
                #
                # below because this script builds swift separately, and people
                # often have reasons to symlink the swift directory into
                # llvm/tools, e.g. to build LLDB.
                cmake_options=(
                    "${cmake_options[@]}"
                    -DCMAKE_C_FLAGS="$(llvm_c_flags ${host})"
                    -DCMAKE_CXX_FLAGS="$(llvm_c_flags ${host})"
                    -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG"
                    -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG"
                    -DCMAKE_BUILD_TYPE:STRING="${LLVM_BUILD_TYPE}"
                    -DLLVM_TOOL_SWIFT_BUILD:BOOL=NO
                    -DLLVM_INCLUDE_DOCS:BOOL=TRUE
                    -DLLVM_ENABLE_LTO:STRING="${LLVM_ENABLE_LTO}"
                    "${llvm_cmake_options[@]}"
                )

                if [[ "${BUILD_TOOLCHAIN_ONLY}" ]]; then
                    cmake_options+=(
                    -DLLVM_BUILD_TOOLS=NO
                    -DLLVM_INSTALL_TOOLCHAIN_ONLY=YES
                    -DLLVM_INCLUDE_TESTS=NO
                    -DCLANG_INCLUDE_TESTS=NO
                    -DLLVM_INCLUDE_UTILS=NO
                    -DLLVM_TOOL_LLI_BUILD=NO
                    -DLLVM_TOOL_LLVM_AR_BUILD=NO
                    -DCLANG_TOOL_CLANG_CHECK_BUILD=NO
                    -DCLANG_TOOL_ARCMT_TEST_BUILD=NO
                    -DCLANG_TOOL_C_ARCMT_TEST_BUILD=NO
                    -DCLANG_TOOL_C_INDEX_TEST_BUILD=NO
                    -DCLANG_TOOL_DRIVER_BUILD=NO
                    -DCLANG_TOOL_DIAGTOOL_BUILD=NO
                    -DCLANG_TOOL_SCAN_BUILD_BUILD=NO
                    -DCLANG_TOOL_SCAN_VIEW_BUILD=NO
                    -DCLANG_TOOL_CLANG_FORMAT_BUILD=NO
                    )
                fi
                
                if [[ $(true_false "${LLVM_INCLUDE_TESTS}") == "FALSE" ]]; then
                    cmake_options+=(
                        -DLLVM_INCLUDE_TESTS=NO
                        -DCLANG_INCLUDE_TESTS=NO
                    )
                fi

                if [[ $(is_cross_tools_host ${host}) ]] ; then
                    cmake_options=(
                        "${cmake_options[@]}"
                        -DLLVM_TABLEGEN=$(build_directory "${LOCAL_HOST}" llvm)/bin/llvm-tblgen
                        -DCLANG_TABLEGEN=$(build_directory "${LOCAL_HOST}" llvm)/bin/clang-tblgen
                        -DLLVM_NATIVE_BUILD=$(build_directory "${LOCAL_HOST}" llvm)
                    )
                fi

                ;;

            swift)

                if [[ "${USE_GOLD_LINKER}" ]]; then
                    # Swift will selectively use the gold linker on all
                    # parts except building the standard library.  We
                    # let the Swift cmake setup figure out how to apply
                    # that.
                    cmake_options=(
                        "${cmake_options[@]}"
                        -DSWIFT_ENABLE_GOLD_LINKER=TRUE
                    )
                fi

                if [[ ! "${SKIP_BUILD_ANDROID}" ]]; then
                    cmake_options=(
                        "${cmake_options[@]}"
                        -DSWIFT_ANDROID_NDK_PATH:STRING="${ANDROID_NDK}"
                        -DSWIFT_ANDROID_NDK_GCC_VERSION:STRING="${ANDROID_NDK_GCC_VERSION}"
                        -DSWIFT_ANDROID_SDK_PATH:STRING="${ANDROID_NDK}/platforms/android-${ANDROID_API_LEVEL}/arch-arm"
                        -DSWIFT_ANDROID_ICU_UC:STRING="${ANDROID_ICU_UC}"
                        -DSWIFT_ANDROID_ICU_UC_INCLUDE:STRING="${ANDROID_ICU_UC_INCLUDE}"
                        -DSWIFT_ANDROID_ICU_I18N:STRING="${ANDROID_ICU_I18N}"
                        -DSWIFT_ANDROID_ICU_I18N_INCLUDE:STRING="${ANDROID_ICU_I18N_INCLUDE}"
                        -DSWIFT_ANDROID_DEPLOY_DEVICE_PATH:STRING="${ANDROID_DEPLOY_DEVICE_PATH}"
                    )
                fi

                native_llvm_tools_path=""
                native_clang_tools_path=""
                native_swift_tools_path=""
                if [[ $(is_cross_tools_host ${host}) ]] ; then

                    # Don't build benchmarks and tests when building cross compiler.
                    build_perf_testsuite_this_time=false
                    build_tests_this_time=false

                    native_llvm_tools_path="$(build_directory "${LOCAL_HOST}" llvm)/bin"
                    native_clang_tools_path="$(build_directory "${LOCAL_HOST}" llvm)/bin"
                    native_swift_tools_path="$(build_directory "${LOCAL_HOST}" swift)/bin"
                else
                    build_perf_testsuite_this_time=$(true_false "$(not ${SKIP_BUILD_BENCHMARKS})")
                    build_tests_this_time=${SWIFT_INCLUDE_TESTS}
                fi

                # Command-line parameters override any autodetection that we
                # might have done.
                if [[ "${NATIVE_LLVM_TOOLS_PATH}" ]] ; then
                    native_llvm_tools_path="${NATIVE_LLVM_TOOLS_PATH}"
                fi
                if [[ "${NATIVE_CLANG_TOOLS_PATH}" ]] ; then
                    native_clang_tools_path="${NATIVE_CLANG_TOOLS_PATH}"
                fi
                if [[ "${NATIVE_SWIFT_TOOLS_PATH}" ]] ; then
                    native_swift_tools_path="${NATIVE_SWIFT_TOOLS_PATH}"
                fi

                if [ "${BUILD_LLVM}" == "0" ] ; then
                    cmake_options=(
                        "${cmake_options[@]}"
                        -DLLVM_TOOLS_BINARY_DIR:PATH=/tmp/dummy
                    )
                fi

                cmake_options=(
                    "${cmake_options[@]}"
                    -DCMAKE_C_FLAGS="$(swift_c_flags ${host})"
                    -DCMAKE_CXX_FLAGS="$(swift_c_flags ${host})"
                    -DCMAKE_C_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG"
                    -DCMAKE_CXX_FLAGS_RELWITHDEBINFO="-O2 -DNDEBUG"
                    -DCMAKE_BUILD_TYPE:STRING="${SWIFT_BUILD_TYPE}"
                    -DLLVM_ENABLE_ASSERTIONS:BOOL=$(true_false "${SWIFT_ENABLE_ASSERTIONS}")
                    -DSWIFT_ANALYZE_CODE_COVERAGE:STRING=$(toupper "${SWIFT_ANALYZE_CODE_COVERAGE}")
                    -DSWIFT_STDLIB_BUILD_TYPE:STRING="${SWIFT_STDLIB_BUILD_TYPE}"
                    -DSWIFT_STDLIB_ASSERTIONS:BOOL=$(true_false "${SWIFT_STDLIB_ENABLE_ASSERTIONS}")
                    -DSWIFT_STDLIB_ENABLE_RESILIENCE:BOOL=$(true_false "${SWIFT_STDLIB_ENABLE_RESILIENCE}")
                    -DSWIFT_STDLIB_SIL_SERIALIZE_ALL:BOOL=$(true_false "${SWIFT_STDLIB_SIL_SERIALIZE_ALL}")
                    -DSWIFT_NATIVE_LLVM_TOOLS_PATH:STRING="${native_llvm_tools_path}"
                    -DSWIFT_NATIVE_CLANG_TOOLS_PATH:STRING="${native_clang_tools_path}"
                    -DSWIFT_NATIVE_SWIFT_TOOLS_PATH:STRING="${native_swift_tools_path}"
                    -DSWIFT_INCLUDE_TOOLS:BOOL=$(true_false "${BUILD_SWIFT_TOOLS}")
                    -DSWIFT_BUILD_REMOTE_MIRROR:BOOL=$(true_false "${BUILD_SWIFT_REMOTE_MIRROR}")
                    -DSWIFT_SERIALIZE_STDLIB_UNITTEST:BOOL=$(true_false "${BUILD_SERIALIZED_STDLIB_UNITTEST}")
                    -DSWIFT_STDLIB_SIL_DEBUGGING:BOOL=$(true_false "${BUILD_SIL_DEBUGGING_STDLIB}")
                    -DSWIFT_CHECK_INCREMENTAL_COMPILATION:BOOL=$(true_false "${CHECK_INCREMENTAL_COMPILATION}")
                    -DSWIFT_BUILD_DYNAMIC_STDLIB:BOOL=$(true_false "${BUILD_SWIFT_DYNAMIC_STDLIB}")
                    -DSWIFT_BUILD_STATIC_STDLIB:BOOL=$(true_false "${BUILD_SWIFT_STATIC_STDLIB}")
                    -DSWIFT_BUILD_DYNAMIC_SDK_OVERLAY:BOOL=$(true_false "${BUILD_SWIFT_DYNAMIC_SDK_OVERLAY}")
                    -DSWIFT_BUILD_STATIC_SDK_OVERLAY:BOOL=$(true_false "${BUILD_SWIFT_STATIC_SDK_OVERLAY}")
                    -DSWIFT_BUILD_PERF_TESTSUITE:BOOL=$(true_false "${build_perf_testsuite_this_time}")
                    -DSWIFT_BUILD_EXAMPLES:BOOL=$(true_false "${BUILD_SWIFT_EXAMPLES}")
                    -DSWIFT_INCLUDE_TESTS:BOOL=$(true_false "${build_tests_this_time}")
                    -DSWIFT_INSTALL_COMPONENTS:STRING="${SWIFT_INSTALL_COMPONENTS}"
                    -DSWIFT_EMBED_BITCODE_SECTION:BOOL=$(true_false "${EMBED_BITCODE_SECTION}")
                    -DSWIFT_TOOLS_ENABLE_LTO:STRING="${SWIFT_TOOLS_ENABLE_LTO}"
                    -DSWIFT_BUILD_RUNTIME_WITH_HOST_COMPILER:BOOL=$(true_false "${BUILD_RUNTIME_WITH_HOST_COMPILER}")
                    "${swift_cmake_options[@]}"
                )

                if [[ "${BUILD_TOOLCHAIN_ONLY}" ]]; then
                    cmake_options+=(
                    -DSWIFT_TOOL_SIL_OPT_BUILD=FALSE
                    -DSWIFT_TOOL_SWIFT_IDE_TEST_BUILD=FALSE
                    -DSWIFT_TOOL_SWIFT_REMOTEAST_TEST_BUILD=FALSE
                    -DSWIFT_TOOL_LLDB_MODULEIMPORT_TEST_BUILD=FALSE
                    -DSWIFT_TOOL_SIL_EXTRACT_BUILD=FALSE
                    -DSWIFT_TOOL_SWIFT_LLVM_OPT_BUILD=FALSE
                    -DSWIFT_TOOL_SWIFT_SDK_ANALYZER_BUILD=FALSE
                    -DSWIFT_TOOL_SWIFT_SDK_DIGESTER_BUILD=FALSE
                    -DSWIFT_TOOL_SOURCEKITD_TEST_BUILD=FALSE
                    -DSWIFT_TOOL_SOURCEKITD_REPL_BUILD=FALSE
                    -DSWIFT_TOOL_COMPLETE_TEST_BUILD=FALSE
                    -DSWIFT_TOOL_SWIFT_REFLECTION_DUMP_BUILD=FALSE
                    )
                fi

                cmake_options=(
                    "${cmake_options[@]}"
                    -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})"
                    -DSWIFT_PATH_TO_CLANG_SOURCE:PATH="${CLANG_SOURCE_DIR}"
                    -DSWIFT_PATH_TO_CLANG_BUILD:PATH="${llvm_build_dir}"
                    -DSWIFT_PATH_TO_LLVM_SOURCE:PATH="${LLVM_SOURCE_DIR}"
                    -DSWIFT_PATH_TO_LLVM_BUILD:PATH="${llvm_build_dir}"
                    -DSWIFT_PATH_TO_CMARK_SOURCE:PATH="${CMARK_SOURCE_DIR}"
                    -DSWIFT_PATH_TO_CMARK_BUILD:PATH="$(build_directory ${host} cmark)"
                    -DSWIFT_PATH_TO_LIBDISPATCH_SOURCE:PATH="${LIBDISPATCH_SOURCE_DIR}"
                    -DSWIFT_PATH_TO_LIBDISPATCH_BUILD:PATH="$(build_directory ${host} libdispatch)"
                )

                if [[ "${CMAKE_GENERATOR}" == "Xcode" ]] ; then
                    cmake_options=(
                        "${cmake_options[@]}"
                        -DSWIFT_CMARK_LIBRARY_DIR:PATH=$(build_directory ${host} cmark)/src/${CMARK_BUILD_TYPE}
                    )
                else
                    cmake_options=(
                        "${cmake_options[@]}"
                        -DSWIFT_CMARK_LIBRARY_DIR:PATH=$(build_directory ${host} cmark)/src
                    )
                fi

                if [[ "${SWIFT_SDKS}" ]] ; then
                    cmake_options=(
                        "${cmake_options[@]}"
                        -DSWIFT_SDKS:STRING="$(join ";" ${SWIFT_SDKS[@]})"
                    )
                fi
                if [[ "${SWIFT_PRIMARY_VARIANT_SDK}" ]] ; then
                    cmake_options=(
                        "${cmake_options[@]}"
                        -DSWIFT_PRIMARY_VARIANT_SDK:STRING="${SWIFT_PRIMARY_VARIANT_SDK}"
                        -DSWIFT_PRIMARY_VARIANT_ARCH:STRING="${SWIFT_PRIMARY_VARIANT_ARCH}"
                    )
                fi

                if contains_product "lldb" ; then
                    lldb_build_dir=$(build_directory ${host} lldb)
                    cmake_options=(
                        "${cmake_options[@]}"
                        -DLLDB_ENABLE:BOOL=TRUE
                        -DLLDB_BUILD_DIR:STRING="${lldb_build_dir}"
                    )
                fi

                build_targets=(all "${SWIFT_STDLIB_TARGETS[@]}")
                if [[ $(true_false "${build_perf_testsuite_this_time}") == "TRUE" ]]; then
                    native_swift_tools_path="$(build_directory_bin ${LOCAL_HOST} swift)"
                    cmake_options=(
                        "${cmake_options[@]}"
                        -DSWIFT_EXEC:STRING="${native_swift_tools_path}/swiftc"
                    )
                    build_targets=("${build_targets[@]}"
                                   "${SWIFT_BENCHMARK_TARGETS[@]}")
                fi

                skip_build=${SKIP_BUILD_SWIFT}
                ;;
            lldb)
                if [ ! -d "${LLDB_SOURCE_DIR}" ]; then
                    echo "error: lldb not found in ${LLDB_SOURCE_DIR}"
                    exit 1
                fi
                if [[ "${CMAKE_GENERATOR}" != "Ninja" ]] ; then
                    echo "error: lldb can only build with ninja"
                    exit 1
                fi
                cmark_build_dir=$(build_directory ${host} cmark)
                lldb_build_dir=$(build_directory ${host} lldb)
                swift_build_dir=$(build_directory ${host} swift)

                # Add any lldb extra cmake arguments here.

                cmake_options=(
                    "${cmake_options[@]}"
                    "${lldb_cmake_options[@]}"
                    )

                if [ ! -z "${LLDB_EXTRA_CMAKE_ARGS}" ]; then
                    cmake_options=(
                        "${cmake_options[@]}"
                        ${LLDB_EXTRA_CMAKE_ARGS}
                        )
                fi

                # Figure out if we think this is a buildbot build.
                # This will influence the lldb version line.
                if [ ! -z "${JENKINS_HOME}" -a ! -z "${JOB_NAME}" -a ! -z "${BUILD_NUMBER}" ]; then
                    LLDB_IS_BUILDBOT_BUILD=1
                else
                    LLDB_IS_BUILDBOT_BUILD=0
                fi

                # Get the build date
                LLDB_BUILD_DATE=$(date +%Y-%m-%d)

                case "${host}" in
                    linux-*)
                        cmake_options=(
                            "${cmake_options[@]}"
                            -DCMAKE_BUILD_TYPE:STRING="${LLDB_BUILD_TYPE}"
                            -DLLDB_SWIFTC:PATH="$(build_directory ${LOCAL_HOST} swift)/bin/swiftc"
                            -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})"
                            -DLLDB_PATH_TO_LLVM_SOURCE:PATH="${LLVM_SOURCE_DIR}"
                            -DLLDB_PATH_TO_CLANG_SOURCE:PATH="${CLANG_SOURCE_DIR}"
                            -DLLDB_PATH_TO_SWIFT_SOURCE:PATH="${SWIFT_SOURCE_DIR}"
                            -DLLDB_PATH_TO_LLVM_BUILD:PATH="${llvm_build_dir}"
                            -DLLDB_PATH_TO_CLANG_BUILD:PATH="${llvm_build_dir}"
                            -DLLDB_PATH_TO_SWIFT_BUILD:PATH="${swift_build_dir}"
                            -DLLDB_PATH_TO_CMARK_BUILD:PATH="${cmark_build_dir}"
                            -DLLDB_IS_BUILDBOT_BUILD="${LLDB_IS_BUILDBOT_BUILD}"
                            -DLLDB_BUILD_DATE:STRING="\"${LLDB_BUILD_DATE}\""
                            -DLLDB_ALLOW_STATIC_BINDINGS=1
                        )
                        ;;
                    freebsd-*)
                        cmake_options=(
                            "${cmake_options[@]}"
                            -DCMAKE_BUILD_TYPE:STRING="${LLDB_BUILD_TYPE}"
                            -DLLDB_SWIFTC:PATH="$(build_directory ${LOCAL_HOST} swift)/bin/swiftc"
                            -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})"
                            -DLLDB_PATH_TO_LLVM_SOURCE:PATH="${LLVM_SOURCE_DIR}"
                            -DLLDB_PATH_TO_CLANG_SOURCE:PATH="${CLANG_SOURCE_DIR}"
                            -DLLDB_PATH_TO_SWIFT_SOURCE:PATH="${SWIFT_SOURCE_DIR}"
                            -DLLDB_PATH_TO_LLVM_BUILD:PATH="${llvm_build_dir}"
                            -DLLDB_PATH_TO_CLANG_BUILD:PATH="${llvm_build_dir}"
                            -DLLDB_PATH_TO_SWIFT_BUILD:PATH="${swift_build_dir}"
                            -DLLDB_PATH_TO_CMARK_BUILD:PATH="${cmark_build_dir}"
                            -DLLDB_IS_BUILDBOT_BUILD="${LLDB_IS_BUILDBOT_BUILD}"
                            -DLLDB_BUILD_DATE:STRING="\"${LLDB_BUILD_DATE}\""
                            -DLLDB_ALLOW_STATIC_BINDINGS=1
                        )
                        ;;
                    cygwin-*)
                        cmake_options=(
                            "${cmake_options[@]}"
                            -DCMAKE_BUILD_TYPE:STRING="${LLDB_BUILD_TYPE}"
                            -DLLDB_SWIFTC:PATH="$(build_directory ${LOCAL_HOST} swift)/bin/swiftc"
                            -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})"
                            -DLLDB_PATH_TO_LLVM_SOURCE:PATH="${LLVM_SOURCE_DIR}"
                            -DLLDB_PATH_TO_CLANG_SOURCE:PATH="${CLANG_SOURCE_DIR}"
                            -DLLDB_PATH_TO_SWIFT_SOURCE:PATH="${SWIFT_SOURCE_DIR}"
                            -DLLDB_PATH_TO_LLVM_BUILD:PATH="${llvm_build_dir}"
                            -DLLDB_PATH_TO_CLANG_BUILD:PATH="${llvm_build_dir}"
                            -DLLDB_PATH_TO_SWIFT_BUILD:PATH="${swift_build_dir}"
                            -DLLDB_PATH_TO_CMARK_BUILD:PATH="${cmark_build_dir}"
                            -DLLDB_IS_BUILDBOT_BUILD="${LLDB_IS_BUILDBOT_BUILD}"
                            -DLLDB_BUILD_DATE:STRING="\"${LLDB_BUILD_DATE}\""
                            -DLLDB_ALLOW_STATIC_BINDINGS=1
                        )
                        ;;
                    macosx-*)
                        # Set up flags to pass to xcodebuild
                        set_lldb_xcodebuild_options
                        set_lldb_build_mode
                        with_pushd ${source_dir} \
                            call xcodebuild -target desktop -configuration ${LLDB_BUILD_MODE} ${lldb_xcodebuild_options[@]}
                        continue
                        ;;
                esac
                ;;
            llbuild)
                cmake_options=(
                    "${cmake_options[@]}"
                    -DCMAKE_INSTALL_PREFIX:PATH="$(get_host_install_prefix ${host})"
                    -DLIT_EXECUTABLE:PATH="${LLVM_SOURCE_DIR}/utils/lit/lit.py"
                    -DFILECHECK_EXECUTABLE:PATH="$(build_directory_bin ${LOCAL_HOST} llvm)/FileCheck"
                    -DCMAKE_BUILD_TYPE:STRING="${LLBUILD_BUILD_TYPE}"
                    -DLLVM_ENABLE_ASSERTIONS:BOOL=$(true_false "${LLBUILD_ENABLE_ASSERTIONS}")
                    # We disable all bindings, since llbuild builds before Swift
                    # and can't use the unbuilt `swiftc`.
                    -DLLBUILD_SUPPORT_BINDINGS:=
                )
                ;;
            swiftpm)
                set_swiftpm_bootstrap_command
                call "${swiftpm_bootstrap_command[@]}"
                
                # swiftpm installs itself with a bootstrap method. No further cmake building is performed.
                continue
                ;;
            xctest)
                SWIFTC_BIN="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc"
                XCTEST_BUILD_DIR=$(build_directory ${host} xctest)
                FOUNDATION_BUILD_DIR=$(build_directory ${host} foundation)
                
                # Staging: require opt-in for building with dispatch
                if [[ ! "${SKIP_BUILD_LIBDISPATCH}" ]] ; then
                    LIBDISPATCH_BUILD_DIR="$(build_directory ${host} libdispatch)"
                    LIBDISPATCH_BUILD_ARGS="--libdispatch-src-dir=${LIBDISPATCH_SOURCE_DIR} --libdispatch-build-dir=${LIBDISPATCH_BUILD_DIR}"
                fi
                
                if [[ "$(uname -s)" == "Darwin" ]] ; then
                    # xcodebuild requires swift-stdlib-tool to build a Swift
                    # framework. This is normally present when building XCTest
                    # via a packaged .xctoolchain, but here we are using the
                    # swiftc that was just built--no toolchain exists yet. As a
                    # result, we must copy swift-stdlib-tool ourselves.
                    copy_swift_stdlib_tool_substitute "$(build_directory_bin ${host} swift)/swift-stdlib-tool"
                fi

                # Use XCTEST_BUILD_TYPE to build either --debug or --release.
                if [[ "${XCTEST_BUILD_TYPE}" ==  "Debug" ]] ; then
                    XCTEST_BUILD_ARGS="--debug"
                else
                    XCTEST_BUILD_ARGS="--release"
                fi

                call "${XCTEST_SOURCE_DIR}"/build_script.py \
                    --swiftc="${SWIFTC_BIN}" \
                    --build-dir="${XCTEST_BUILD_DIR}" \
                    --foundation-build-dir="${FOUNDATION_BUILD_DIR}/Foundation" \
                    $LIBDISPATCH_BUILD_ARGS \
                    $XCTEST_BUILD_ARGS

                # XCTest builds itself and doesn't rely on cmake
                continue
                ;;
            foundation)
                # The configuration script requires knowing about XCTest's
                # location for building and running the tests. Note that XCTest
                # is not yet built at this point.
                XCTEST_BUILD_DIR=$(build_directory ${host} xctest)
                SWIFTC_BIN="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc"
                SWIFT_BIN="$(build_directory_bin ${LOCAL_HOST} swift)/swift"
                SWIFT_BUILD_PATH="$(build_directory ${host} swift)"
                LLVM_BIN="$(build_directory_bin ${LOCAL_HOST} llvm)"

                # Staging: require opt-in for building with dispatch
                if [[ ! "${SKIP_BUILD_LIBDISPATCH}" ]] ; then
                    LIBDISPATCH_BUILD_DIR="$(build_directory ${host} libdispatch)"
                    LIBDISPATCH_BUILD_ARGS="-DLIBDISPATCH_SOURCE_DIR=${LIBDISPATCH_SOURCE_DIR} -DLIBDISPATCH_BUILD_DIR=${LIBDISPATCH_BUILD_DIR}"
                fi

                if [[ "${USE_GOLD_LINKER}" ]]; then
                    SWIFT_USE_LINKER="-fuse-ld=gold"
                fi

                # FIXME CROSSCOMPILING: 
                # Foundation is a target library (like the Swift standard library),
                # so technically we should build it for all stdlib_targets, not just for the host.
                # However, we only have the triple and sysroot for the host.
                # Also, we will need to tell it which linker to use.
                FOUNDATION_BUILD_ARGS=()
                if [[ $(is_cross_tools_host ${host}) ]]; then
                    FOUNDATION_BUILD_ARGS+=(
                        "--target=${SWIFT_HOST_TRIPLE}"
                    )
                fi

                # FIXME: Foundation doesn't build from the script on OS X
                if [[ ${host} == "macosx"* ]]; then
                    echo "Skipping Foundation on OS X -- use the Xcode project instead"
                    continue
                fi
    
                with_pushd "${FOUNDATION_SOURCE_DIR}" \
                    call env SWIFTC="${SWIFTC_BIN}" CLANG="${LLVM_BIN}"/clang SWIFT="${SWIFT_BIN}" \
                      SDKROOT="${SWIFT_BUILD_PATH}" BUILD_DIR="${build_dir}" DSTROOT="$(get_host_install_destdir ${host})" PREFIX="$(get_host_install_prefix ${host})" ./configure "${FOUNDATION_BUILD_TYPE}" ${FOUNDATION_BUILD_ARGS[@]} -DXCTEST_BUILD_DIR=${XCTEST_BUILD_DIR} $LIBDISPATCH_BUILD_ARGS
                with_pushd "${FOUNDATION_SOURCE_DIR}" \
                    call ${NINJA_BIN}

                # Foundation builds itself and doesn't use cmake
                continue
                ;;
            libdispatch)
                LIBDISPATCH_BUILD_DIR=$(build_directory ${host} ${product})
                SWIFT_BUILD_PATH="$(build_directory ${host} swift)"
                SWIFTC_BIN="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc"
                LLVM_BIN="$(build_directory_bin ${LOCAL_HOST} llvm)"

                if [[ "${RECONFIGURE}" || ! -f "${LIBDISPATCH_BUILD_DIR}"/config.status ]]; then
                    echo "Reconfiguring libdispatch"
                    # First time building; need to run autotools and configure
                    if [[ "$LIBDISPATCH_BUILD_TYPE" == "Release" ]] ; then
                        dispatch_build_variant_arg="release"
                    elif [[ "$LIBDISPATCH_BUILD_TYPE" == "RelWithDebInfo" ]]; then
                        dispatch_build_variant_arg="releasedebuginfo"
                    else
                        dispatch_build_variant_arg="debug"
                    fi
                    call mkdir -p "${LIBDISPATCH_BUILD_DIR}"
                    with_pushd "${LIBDISPATCH_SOURCE_DIR}" \
                        call autoreconf -fvi
                    with_pushd "${LIBDISPATCH_BUILD_DIR}" \
                        call env CC="${LLVM_BIN}/clang" CXX="${LLVM_BIN}/clang++" SWIFTC="${SWIFTC_BIN}" \
                            "${LIBDISPATCH_SOURCE_DIR}"/configure --with-swift-toolchain="${SWIFT_BUILD_PATH}" \
                            --with-build-variant=$dispatch_build_variant_arg \
                            --prefix="$(get_host_install_destdir ${host})$(get_host_install_prefix ${host})"
                else
                    echo "Skipping reconfiguration of libdispatch"
                fi
                with_pushd "${LIBDISPATCH_BUILD_DIR}" \
                    call make
                with_pushd "${LIBDISPATCH_BUILD_DIR}/tests" \
                    call make build-tests

                # libdispatch builds itself and doesn't use cmake
                continue
                ;;
            playgroundlogger)
                PLAYGROUNDLOGGER_BUILD_DIR=$(build_directory ${host} ${product})
                SWIFTC_BIN="$(build_directory_bin ${host} swift)/swiftc"

                set -x
                pushd "${PLAYGROUNDLOGGER_SOURCE_DIR}"
                mkdir -p "${PLAYGROUNDLOGGER_BUILD_DIR}"
                "${playgroundlogger_build_cmd}" -configuration "${PLAYGROUNDLOGGER_BUILD_TYPE}" -target "${playgroundlogger_build_target}" install SWIFT_EXEC="${SWIFTC_BIN}" DSTROOT=${build_dir} INSTALL_PATH="/" SKIP_INSTALL=NO
                popd
                { set +x; } 2>/dev/null
                continue
                ;;
            playgroundsupport)
                PLAYGROUNDSUPPORT_BUILD_DIR=$(build_directory ${host} ${product})
                SWIFTC_BIN="$(build_directory_bin ${host} swift)/swiftc"

                set -x
                pushd "${PLAYGROUNDSUPPORT_SOURCE_DIR}"
                mkdir -p "${PLAYGROUNDSUPPORT_BUILD_DIR}"
                "xcodebuild" -configuration "${PLAYGROUNDSUPPORT_BUILD_TYPE}" -target AllProducts SWIFT_EXEC="${SWIFTC_BIN}" DSTROOT="$(get_host_install_destdir ${host})"
                popd
                { set +x; } 2>/dev/null
                continue
                ;;
            *)
                echo "error: unknown product: ${product}"
                exit 1
                ;;
        esac

        # Compute the generator output file to check for, to determine if we
        # must reconfigure. We only handle Ninja for now.
        #
        # This is important for ensuring that if a CMake configuration fails in
        # CI, that we will still be willing to rerun the configuration process.
        generator_output_path=""
        if [[ "${CMAKE_GENERATOR}" == "Ninja" ]] ; then
            generator_output_path="${build_dir}/build.ninja"
        fi

        # Configure if necessary.
        cmake_cache_path="${build_dir}/CMakeCache.txt"
        if [[  "${RECONFIGURE}" || ! -f "${cmake_cache_path}" || \
                    ( ! -z "${generator_output_path}" && ! -f "${generator_output_path}" ) ]] ; then
            call mkdir -p "${build_dir}"
            if [[ -n "${DISTCC}" ]]; then
                EXTRA_DISTCC_OPTIONS=("DISTCC_HOSTS=localhost,lzo,cpp")
            fi
            with_pushd "${build_dir}" \
                call env "${EXTRA_DISTCC_OPTIONS[@]}" "${CMAKE}" "${cmake_options[@]}" "${EXTRA_CMAKE_OPTIONS[@]}" "${source_dir}"
        fi

        # When we are building LLVM create symlinks to the c++ headers. We need
        # to do this before building LLVM since compiler-rt depends on being
        # built with the just built clang compiler. These are normally put into
        # place during the cmake step of LLVM's build when libcxx is in
        # tree... but we are not building llvm with libcxx in tree when we build
        # swift. So we need to do configure's work here.
        if [[ "${product}" == "llvm" ]]; then
            # Find the location of the c++ header dir.
            if [[ "$(uname -s)" == "Darwin" ]] ; then
              HOST_CXX_DIR=$(dirname ${HOST_CXX})
              HOST_CXX_HEADERS_DIR="$HOST_CXX_DIR/../../usr/include/c++"
            else # Linux
              HOST_CXX_HEADERS_DIR="/usr/include/c++"
            fi

            # Find the path in which the local clang build is expecting to find
            # the c++ header files.
            BUILT_CXX_INCLUDE_DIR="$llvm_build_dir/include"

            echo "symlinking the system headers ($HOST_CXX_HEADERS_DIR) into the local clang build directory ($BUILT_CXX_INCLUDE_DIR)."
            call ln -s -f "$HOST_CXX_HEADERS_DIR" "$BUILT_CXX_INCLUDE_DIR"
        fi

        # Build.
        if [[ ! "${skip_build}" ]]; then
            if [[ "${CMAKE_GENERATOR}" == "Xcode" ]] ; then
                # Xcode generator uses "ALL_BUILD" instead of "all".
                # Also, xcodebuild uses -target instead of bare names.
                build_targets=("${build_targets[@]/all/ALL_BUILD}")
                build_targets=("${build_targets[@]/#/${BUILD_TARGET_FLAG} }")

                # Xcode can't restart itself if it turns out we need to reconfigure.
                # Do an advance build to handle that.
                call "${CMAKE_BUILD[@]}" "${build_dir}" $(cmake_config_opt ${product})
            fi

            call "${CMAKE_BUILD[@]}" "${build_dir}" $(cmake_config_opt ${product}) -- "${BUILD_ARGS[@]}" ${build_targets[@]}
        fi
    done
done
# END OF BUILD PHASE

# Trap function to print the current test configuration when tests fail.
# This is a function so the text is not unnecessarily displayed when running -x.
tests_busted ()
{
    echo "*** Failed while running tests for $1 $2"
}

for host in "${ALL_HOSTS[@]}"; do
    # Skip this pass when the only action to execute can't match.
    if ! [[ $(should_execute_host_actions_for_phase ${host} test) ]]; then
        continue
    fi

    # Calculate test targets
    calculate_targets_for_host $host

    # Run the tests for each product
    for product in "${PRODUCTS[@]}"; do
        # Check if we should perform this action.
        if ! [[ $(should_execute_action "${host}-${product}-test") ]]; then
            continue
        fi

        case ${product} in
            cmark)
                if [[ "${SKIP_TEST_CMARK}" ]]; then
                    continue
                fi
                executable_target=api_test
                results_targets=(test)
                if [[ "${CMAKE_GENERATOR}" == "Xcode" ]]; then
                    # Xcode generator uses "RUN_TESTS" instead of "test".
                    results_targets=(RUN_TESTS)
                fi
                ;;
            llvm)
                continue # We don't test LLVM
                ;;
            swift)
                executable_target=
                results_targets=
                if ! [[ "${SKIP_TEST_SWIFT}" ]]; then
                    executable_target=SwiftUnitTests
                    results_targets=("${SWIFT_TEST_TARGETS[@]}")
                    if [[ "${STRESS_TEST_SOURCEKIT}" ]]; then
                        results_targets=(
                            "${results_targets[@]}"
                            stress-SourceKit
                        )
                    fi
                fi
                if ! [[ "${SKIP_TEST_BENCHMARKS}" ]]; then
                    results_targets=(
                        "${results_targets[@]}"
                        "${SWIFT_RUN_BENCHMARK_TARGETS[@]}"
                    )
                fi
                if [[ -z "${results_targets[@]}" ]]; then
                    continue
                fi
                ;;
            lldb)
                if [[ "${SKIP_TEST_LLDB}" ]]; then
                    continue
                fi
                lldb_build_dir=$(build_directory ${host} lldb)

                # Run the gtests.
                if [[ "$(uname -s)" == "Darwin" ]] ; then
                    set_lldb_xcodebuild_options
                    # Run the LLDB unittests (gtests).
                    with_pushd ${LLDB_SOURCE_DIR} \
                               call xcodebuild -scheme lldb-gtest -configuration ${LLDB_BUILD_MODE} ${lldb_xcodebuild_options[@]}
                    rc=$?
                    if [[ "$rc" -ne 0 ]] ; then
                        >&2 echo "error: LLDB gtests failed"
                        exit 1
                    fi
                else
                    # FIXME run the gtests on other platforms.
                    # There should be a CMake target for this already.
                    echo Run LLDB gtests here.
                fi

                swift_build_dir=$(build_directory ${host} swift)
                # Setup lldb executable path
                if [[ "$(uname -s)" == "Darwin" ]] ; then
                    lldb_executable="${lldb_build_dir}"/${LLDB_BUILD_MODE}/lldb
                else
                    lldb_executable="${lldb_build_dir}"/bin/lldb
                fi

                results_dir="${lldb_build_dir}/test-results"

                # Handle test results formatter
                if [[ "${LLDB_TEST_WITH_CURSES}" ]]; then
                    # Setup the curses results formatter.
                    LLDB_FORMATTER_OPTS="\
                                       --results-formatter lldbsuite.test_event.formatter.curses.Curses \
                                       --results-file /dev/stdout"
                else
                    LLDB_FORMATTER_OPTS="\
                                       --results-formatter lldbsuite.test_event.formatter.xunit.XunitFormatter \
                                       --results-file ${results_dir}/results.xml \
                                       -O--xpass=success \
                                       -O--xfail=success"
                    # Setup the xUnit results formatter.
                    if [[ "$(uname -s)" != "Darwin" ]] ; then
                        # On non-Darwin, we ignore skipped tests entirely
                        # so that they don't pollute our xUnit results with
                        # non-actionable content.
                        LLDB_FORMATTER_OPTS="${LLDB_FORMATTER_OPTS} -O-ndsym -O-rdebugserver -O-rlibc\\\\+\\\\+ -O-rlong.running -O-rbenchmarks -O-rrequires.one?.of.darwin"
                    fi
                fi

                # Handle test subdirectory clause
                if [[ "${LLDB_TEST_SWIFT_ONLY}" ]]; then
                    LLDB_TEST_SUBDIR_CLAUSE="--test-subdir lang/swift"
                else
                    LLDB_TEST_SUBDIR_CLAUSE=""
                fi

                # figure out which C/C++ compiler we should use for building test inferiors.
                if [[ "${LLDB_TEST_CC}" == "host-toolchain" ]]; then
                    # Use the host toolchain: i.e. the toolchain specified by HOST_CC
                    LLDB_DOTEST_CC_OPTS="-C ${HOST_CC}"
                elif [[ -n "${LLDB_TEST_CC}" ]]; then
                    # Use exactly the compiler path specified by the user.
                    LLDB_DOTEST_CC_OPTS="-C ${LLDB_TEST_CC}"
                else
                    # Use the clang that was just built in the tree.
                    LLDB_DOTEST_CC_OPTS="-C $(build_directory $LOCAL_HOST llvm)"/bin/clang
                fi
                
                call mkdir -p "${results_dir}"
                with_pushd "${results_dir}" \
                           call env SWIFTCC="$(build_directory $LOCAL_HOST swift)/bin/swiftc" \
                           SWIFTLIBS="${swift_build_dir}/lib/swift" \
                           "${LLDB_SOURCE_DIR}"/test/dotest.py \
                           --executable "${lldb_executable}" \
                           --rerun-all-issues \
                           ${LLDB_TEST_SUBDIR_CLAUSE} \
                           ${LLDB_DOTEST_CC_OPTS} \
                           ${LLDB_FORMATTER_OPTS}
                continue
                ;;
            llbuild)
                if [[ "${SKIP_TEST_LLBUILD}" ]]; then
                    continue
                fi
                results_targets=("test")
                executable_target=""
                ;;
            swiftpm)
                if [[ "${SKIP_TEST_SWIFTPM}" ]]; then
                    continue
                fi
                echo "--- Running tests for ${product} ---"
                call "${swiftpm_bootstrap_command[@]}" test
                # As swiftpm tests itself, we break early here.
                continue
                ;;
            xctest)
                if [[ "${SKIP_TEST_XCTEST}" ]]; then
                    continue
                fi
                # If libdispatch is being built then XCTest will need access to it
                if [[ ! "${SKIP_BUILD_LIBDISPATCH}" ]] ; then
                    LIBDISPATCH_BUILD_DIR="$(build_directory ${host} libdispatch)"
                    LIBDISPATCH_BUILD_ARGS="--libdispatch-src-dir=${LIBDISPATCH_SOURCE_DIR} --libdispatch-build-dir=${LIBDISPATCH_BUILD_DIR}"
                fi

                # Use XCTEST_BUILD_TYPE to build either --debug or --release.
                if [[ "${XCTEST_BUILD_TYPE}" ==  "Debug" ]] ; then
                    XCTEST_BUILD_ARGS="--debug"
                else
                    XCTEST_BUILD_ARGS="--release"
                fi

                echo "--- Running tests for ${product} ---"
                SWIFTC_BIN="$(build_directory_bin ${LOCAL_HOST} swift)/swiftc"
                FOUNDATION_BUILD_DIR=$(build_directory ${host} foundation)
                XCTEST_BUILD_DIR=$(build_directory ${host} xctest)
                call "${XCTEST_SOURCE_DIR}"/build_script.py test \
                    --swiftc="${SWIFTC_BIN}" \
                    --foundation-build-dir="${FOUNDATION_BUILD_DIR}/Foundation" \
                    ${LIBDISPATCH_BUILD_ARGS} \
                    $XCTEST_BUILD_ARGS \
                    "${XCTEST_BUILD_DIR}"
                echo "--- Finished tests for ${product} ---"
                continue
                ;;
            foundation)
                # FIXME: Foundation doesn't build from the script on OS X
                if [[ ${host} == "macosx"* ]]; then
                    echo "Skipping Foundation on OS X -- use the Xcode project instead"
                    continue
                fi
                if [[ "${SKIP_TEST_FOUNDATION}" ]]; then
                    continue
                fi
                # If libdispatch is being built, TestFoundation will need access to it
                if [[ ! "${SKIP_BUILD_LIBDISPATCH}" ]] ; then
                    LIBDISPATCH_LIB_DIR=":$(build_directory ${host} libdispatch)/src/.libs"
                else
                    LIBDISPATCH_LIB_DIR=""
                fi
                echo "--- Running tests for ${product} ---"
                build_dir=$(build_directory ${host} ${product})
                XCTEST_BUILD_DIR=$(build_directory ${host} xctest)
                with_pushd "${FOUNDATION_SOURCE_DIR}" \
                    call ${NINJA_BIN} TestFoundation
                call env LD_LIBRARY_PATH="$(get_host_install_destdir ${host})$(get_host_install_prefix ${host})"/lib/swift/:"${build_dir}/Foundation":"${XCTEST_BUILD_DIR}""${LIBDISPATCH_LIB_DIR}":${LD_LIBRARY_PATH} "${build_dir}"/TestFoundation/TestFoundation
                echo "--- Finished tests for ${product} ---"
                continue
                ;;
            libdispatch)
                if [[ "${SKIP_TEST_LIBDISPATCH}" ]]; then
                    continue
                fi
                LIBDISPATCH_BUILD_DIR=$(build_directory ${host} ${product})
                echo "--- Running tests for ${product} ---"
                with_pushd "${LIBDISPATCH_BUILD_DIR}" \
                    call env VERBOSE=1 make check
                echo "--- Finished tests for ${product} ---"
                continue
                ;;
           playgroundlogger)
               SWIFT_DYLIB_PATH=$(build_directory ${host} swift)/lib/swift/macosx/
               PLAYGROUNDLOGGER_FRAMEWORK_PATH=$(build_directory ${host} ${product})
               set -x
               pushd "${PLAYGROUNDLOGGER_FRAMEWORK_PATH}"
               DYLD_LIBRARY_PATH=$SWIFT_DYLIB_PATH DYLD_FRAMEWORK_PATH=$PLAYGROUNDLOGGER_FRAMEWORK_PATH ./PlaygroundLogger_TestDriver
               popd
               { set +x; } 2>/dev/null
               continue
               ;;
           playgroundsupport)
               continue
               ;;
            *)
                echo "error: unknown product: ${product}"
                exit 1
                ;;
        esac

        trap "tests_busted ${product} ''" ERR
        build_dir=$(build_directory ${host} ${product})
        build_cmd=("${CMAKE_BUILD[@]}" "${build_dir}" $(cmake_config_opt ${product}) -- "${BUILD_ARGS[@]}")

        if [[ "${executable_target}" != "" ]]; then
            echo "--- Building tests for ${product} ---"
            call "${build_cmd[@]}" ${BUILD_TARGET_FLAG} "${executable_target}"
        fi

        # We can only run tests built for the host machine, because
        # cross-compiled hosts only build their native target. See: get_stdlib_targets_for_host()
        if [[ $(is_cross_tools_host ${host}) ]]; then
            echo "--- Can't execute tests for ${host}, skipping... ---"
            continue
        fi

        echo "--- Running tests for ${product} ---"
        for target in "${results_targets[@]}"; do
            if [[ "${target}" != "" ]]; then
                echo "--- ${target} ---"
                trap "tests_busted ${product} '(${target})'" ERR

                # NOTE: In dry-run mode, build_dir might not exist yet. In that
                #       case, -n query will fail. So, in dry-run mode,
                #       we don't expand test script.
                if [[ ! "${DRY_RUN}" && "${CMAKE_GENERATOR}" == Ninja ]] && !( "${build_cmd[@]}" --version 2>&1 | grep -i -q llbuild ) && [[ -z "${DISTCC_PUMP}" ]]; then
                    # Ninja buffers command output to avoid scrambling the output
                    # of parallel jobs, which is awesome... except that it
                    # interferes with the progress meter when testing.  Instead of
                    # executing ninja directly, have it dump the commands it would
                    # run, strip Ninja's progress prefix with sed, and tell the
                    # shell to execute that.
                    # However, if we do this in a subshell in the ``sh -e -x -c`` line,
                    # errors in the command will not stop the script as they should.
                    echo "Generating dry run test command from: ${build_cmd[@]} -n -v ${target}"
                    dry_run_command_output="$(${build_cmd[@]} -n -v ${target} | sed -e 's/[^]]*] //')"
                    echo "Test command: ${dry_run_command_output}"
                    sh -e -x -c "${dry_run_command_output}"
                else
                    call "${build_cmd[@]}" ${BUILD_TARGET_FLAG} ${target}
                fi
                echo "-- ${target} finished --"
            fi
        done

        trap - ERR
        echo "--- Finished tests for ${product} ---"
    done
done
# END OF TEST PHASE


LIPO_SRC_DIRS=()

for host in "${ALL_HOSTS[@]}"; do
    # Skip this pass when the only action to execute can't match.
    if ! [[ $(should_execute_host_actions_for_phase ${host} install) ]]; then
        continue
    fi

    # Skip this pass if flag is set and we are cross compiling and it's the local host.
    if [[ "${SKIP_LOCAL_HOST_INSTALL}" ]] && [[ $(has_cross_compile_hosts) ]] && [[ ${host} == ${LOCAL_HOST} ]]; then
        continue
    fi

    # Calculate the directory to install products in to.
    host_install_destdir=$(get_host_install_destdir ${host})
    host_install_prefix=$(get_host_install_prefix ${host})
    
    if [[ $(should_include_host_in_lipo ${host}) ]]; then
        LIPO_SRC_DIRS+=( "${host_install_destdir}" )
    fi

    # Set the build options for this host
    set_build_options_for_host $host

    for product in "${PRODUCTS[@]}"; do
        # Check if we should perform this action.
        if ! [[ $(should_execute_action "${host}-${product}-install") ]]; then
            continue
        fi

        INSTALL_TARGETS="install"

        case ${product} in
            cmark)
                if [[ -z "${INSTALL_CMARK}" ]] ; then
                    continue
                fi
                ;;
            llvm)
                if [[ -z "${LLVM_INSTALL_COMPONENTS}" ]] ; then
                    continue
                fi
                INSTALL_TARGETS=install-$(echo ${LLVM_INSTALL_COMPONENTS} | sed -E 's/;/ install-/g')
                ;;
            swift)
                if [[ -z "${INSTALL_SWIFT}" ]] ; then
                    continue
                fi
                ;;
            llbuild)
                if [[ -z "${INSTALL_LLBUILD}" ]] ; then
                    continue
                fi
                INSTALL_TARGETS=install-swift-build-tool
                ;;
            # Products from this here install themselves; they don't fall-through.
            lldb)
                if [[ -z "${INSTALL_LLDB}" ]] ; then
                    continue
                fi
                if [[ -z "${INSTALL_DESTDIR}" ]] ; then
                    echo "--install-destdir is required to install products."
                    exit 1
                fi

                case ${host} in
                    linux-*)
                        ;;
                    freebsd-*)
                        ;;
                    cygwin-*)
                        ;;
                    macosx-*)
                        set_lldb_build_mode
                        with_pushd ${LLDB_SOURCE_DIR} \
                            call xcodebuild -target toolchain -configuration ${LLDB_BUILD_MODE} install ${lldb_xcodebuild_options[@]} DSTROOT="${host_install_destdir}" LLDB_TOOLCHAIN_PREFIX="${TOOLCHAIN_PREFIX}"
                        continue
                        ;;
                esac
                ;;
            swiftpm)
                if [[ -z "${INSTALL_SWIFTPM}" ]] ; then
                    continue
                fi
                if [[ -z "${INSTALL_DESTDIR}" ]] ; then
                    echo "--install-destdir is required to install products."
                    exit 1
                fi

                echo "--- Installing ${product} ---"
                call "${swiftpm_bootstrap_command[@]}" --prefix="${host_install_destdir}${host_install_prefix}" install
                # As swiftpm bootstraps the installation itself, we break early here.
                continue
                ;;
            xctest)
                if [[ -z "${INSTALL_XCTEST}" ]] ; then
                    continue
                fi
                if [[ -z "${INSTALL_DESTDIR}" ]] ; then
                    echo "--install-destdir is required to install products."
                    exit 1
                fi

                case ${host} in
                    linux-*)
                        LIB_TARGET="linux"
                        ;;
                    freebsd-*)
                        LIB_TARGET="freebsd"
                        ;;
                    cygwin-*)
                        LIB_TARGET="windows"
                        ;;
                    *)
                        echo "error: --install-xctest is not supported on this platform"
                        exit 1
                        ;;
                esac

                echo "--- Installing ${product} ---"
                XCTEST_BUILD_DIR=$(build_directory ${host} xctest)
                XCTEST_INSTALL_PREFIX="${host_install_destdir}${host_install_prefix}/lib/swift/${LIB_TARGET}"
                # Note that installing directly to /usr/lib/swift usually
                # requires root permissions.
                call "${XCTEST_SOURCE_DIR}"/build_script.py install \
                    --library-install-path="${XCTEST_INSTALL_PREFIX}" \
                    --module-install-path="${XCTEST_INSTALL_PREFIX}"/"${SWIFT_HOST_VARIANT_ARCH}" \
                    "${XCTEST_BUILD_DIR}"

                # As XCTest installation is self-contained, we break early here.
                continue
                ;;
            foundation)
                # FIXME: Foundation doesn't build from the script on OS X
                if [[ ${host} == "macosx"* ]]; then
                    echo "Skipping Foundation on OS X -- use the Xcode project instead"
                    continue
                fi
                if [[ -z "${INSTALL_FOUNDATION}" ]] ; then
                    continue
                fi
                if [[ -z "${INSTALL_DESTDIR}" ]] ; then
                    echo "--install-destdir is required to install products."
                    exit 1
                fi
                echo "--- Installing ${product} ---"
                build_dir=$(build_directory ${host} ${product})
                with_pushd "${FOUNDATION_SOURCE_DIR}" \
                    call ${NINJA_BIN} install

                # As foundation installation is self-contained, we break early here.
                continue
                ;;
            libdispatch)
                if [[ -z "${INSTALL_LIBDISPATCH}" ]] ; then
                    continue
                fi
                if [[ -z "${INSTALL_DESTDIR}" ]] ; then
                    echo "--install-destdir is required to install products."
                    exit 1
                fi
                echo "--- Installing ${product} ---"
                LIBDISPATCH_BUILD_DIR=$(build_directory ${host} ${product})
                with_pushd "${LIBDISPATCH_BUILD_DIR}" \
                    call make install

                # As libdispatch installation is self-contained, we break early here.
                continue
                ;;
            playgroundlogger)
                if [[ -z "${INSTALL_PLAYGROUNDLOGGER}" ]] ; then
                    continue
                fi
                if [[ -z "${INSTALL_DESTDIR}" ]] ; then
                    echo "--install-destdir is required to install products."
                    exit 1
                fi

                echo "--- Installing ${product} ---"
                PLAYGROUNDLOGGER_BUILD_DIR=$(build_directory ${host} playgroundlogger)
                PLAYGROUNDLOGGER_INSTALL_PREFIX="${INSTALL_DESTDIR}"
                # Note that installing directly to /usr/lib/swift usually
                # requires root permissions.
                set -x
                case "$(uname -s)" in
                    Linux)
                        PLAYGROUNDLOGGER_INSTALL_DIR="$(get_host_install_destdir ${host})/$(get_host_install_prefix ${host})/lib/swift/linux"
                        mkdir -p "${PLAYGROUNDLOGGER_INSTALL_DIR}"
                        cp -R "${PLAYGROUNDLOGGER_BUILD_DIR}"/libPlaygroundLogger.so "${PLAYGROUNDLOGGER_INSTALL_DIR}"
                        ;;
                    Darwin)
                        pushd "${PLAYGROUNDLOGGER_SOURCE_DIR}"
                        xcodebuild -target "All Platforms Logger" -configuration Toolchain_${PLAYGROUNDLOGGER_BUILD_TYPE} install SWIFT_EXEC="${SWIFTC_BIN}" DT_TOOLCHAIN_DIR="${TOOLCHAIN_PREFIX}" DSTROOT="$(get_host_install_destdir ${host})"
                        popd
                        continue
                        ;;
                    *)
                        echo "error: --install-playgroundlogger is not supported on this platform"
                        exit 1
                        ;;
                esac
                { set +x; } 2>/dev/null

                # As XCTest installation is self-contained, we break early here.
                continue
                ;;
            playgroundsupport)
                set -x
                if [[ -z "${INSTALL_PLAYGROUNDSUPPORT}" ]] ; then
                    continue
                fi
                case "$(uname -s)" in
                    Linux)
                        ;;
                    FreeBSD)
                        ;;
                    CYGWIN_NT-10.0)
                        ;;
                    Darwin)
                        pushd "${PLAYGROUNDSUPPORT_SOURCE_DIR}"
                        xcodebuild -target AllProducts -configuration ${PLAYGROUNDSUPPORT_BUILD_TYPE} install SWIFT_EXEC="${SWIFTC_BIN}" DT_TOOLCHAIN_DIR="${TOOLCHAIN_PREFIX}" DSTROOT="$(get_host_install_destdir ${host})"
                        popd
                        continue
                        ;;
                esac
                { set +x; } 2>/dev/null
                ;;
            *)
                echo "error: unknown product: ${product}"
                exit 1
                ;;
        esac

        if [[ -z "${INSTALL_DESTDIR}" ]] ; then
            echo "--install-destdir is required to install products."
            exit 1
        fi

        echo "--- Installing ${product} ---"
        build_dir=$(build_directory ${host} ${product})

        call env DESTDIR="${host_install_destdir}" "${CMAKE_BUILD[@]}" "${build_dir}" -- ${INSTALL_TARGETS}
    done

    if [[ "${DARWIN_INSTALL_EXTRACT_SYMBOLS}" ]] && [[ $(host_has_darwin_symbols ${host}) ]]; then
        echo "--- Extracting symbols ---"

        # FIXME: Since it's hard to trace output pipe call,
        #        For now, We don't support dry-run trace for this block
        #        Instead, just echo we do "darwin_intall_extract_symbols".
        if [[ "${DRY_RUN}" ]]; then
            call darwin_install_extract_symbols
        else
            set -x
            # Copy executables and shared libraries from the `host_install_destdir` to
            # INSTALL_SYMROOT and run dsymutil on them.
            (cd "${host_install_destdir}" &&
             find ./"${TOOLCHAIN_PREFIX}" -perm -0111 -type f -print | cpio -pdm "${INSTALL_SYMROOT}")

            # Run dsymutil on executables and shared libraries.
            #
            # Exclude shell scripts.
            (cd "${INSTALL_SYMROOT}" &&
             find ./"${TOOLCHAIN_PREFIX}" -perm -0111 -type f -print | \
               grep -v swift-stdlib-tool | \
               grep -v crashlog.py | \
               grep -v symbolication.py | \
               xargs -n 1 -P ${BUILD_JOBS} $(xcrun_find_tool dsymutil))

            # Strip executables, shared libraries and static libraries in
            # `host_install_destdir`.
            find "${host_install_destdir}${TOOLCHAIN_PREFIX}/" \
              '(' -perm -0111 -or -name "*.a" ')' -type f -print | \
              xargs -n 1 -P ${BUILD_JOBS} $(xcrun_find_tool strip) -S

            { set +x; } 2>/dev/null
        fi
    fi
done
# Everything is 'installed', but some products may be awaiting lipo.


function build_and_test_installable_package() {

    local host="$1"

    if [[ "${INSTALLABLE_PACKAGE}" ]] ; then

        # Get the directory where the products where installed.
        # If INSTALL_DESTDIR not given, we couldn't have installed anything.
        
        if [[ -z "${INSTALL_DESTDIR}" ]] ; then
            echo "--install-destdir required to build a package. Skipping."
            return
        fi
        local host_install_destdir="$(get_host_install_destdir ${host})"
        local host_install_prefix="$(get_host_install_prefix ${host})"

        if [[ $(has_cross_compile_hosts) ]]; then
            package_for_host="${INSTALLABLE_PACKAGE}-${host}"
        else
            package_for_host="${INSTALLABLE_PACKAGE}"
        fi

        echo "--- Creating installable package ---"
        echo "-- Package file: ${package_for_host} --"

        # Assume the lipo builds are (or include) an OS X host and build an xctoolchain
        if [[ "${host}" == "macosx-"* ]] || [[ "${host}" == "merged-hosts" ]]; then
          copy_swift_stdlib_tool_substitute "${host_install_destdir}${host_install_prefix}/bin/swift-stdlib-tool"
          
          # Create plist for xctoolchain.
          echo "-- Create Info.plist --"
          PLISTBUDDY_BIN="/usr/libexec/PlistBuddy"

          DARWIN_TOOLCHAIN_INSTALL_LOCATION="/Library/Developer/Toolchains/${DARWIN_TOOLCHAIN_NAME}.xctoolchain"
          DARWIN_TOOLCHAIN_INFO_PLIST="${host_install_destdir}${TOOLCHAIN_PREFIX}/Info.plist"
          DARWIN_TOOLCHAIN_REPORT_URL="https://bugs.swift.org/"
          COMPATIBILITY_VERSION=2
          COMPATIBILITY_VERSION_DISPLAY_STRING="Xcode 8.0"
          DARWIN_TOOLCHAIN_CREATED_DATE="$(date -u +'%a %b %d %T GMT %Y')"

          echo "-- Removing: ${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call rm -f ${DARWIN_TOOLCHAIN_INFO_PLIST}

          call ${PLISTBUDDY_BIN} -c "Add DisplayName string '${DARWIN_TOOLCHAIN_DISPLAY_NAME}'" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add ShortDisplayName string '${DARWIN_TOOLCHAIN_DISPLAY_NAME_SHORT}'" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add CreatedDate date '${DARWIN_TOOLCHAIN_CREATED_DATE}'" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add CompatibilityVersion integer ${COMPATIBILITY_VERSION}" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add CompatibilityVersionDisplayString string ${COMPATIBILITY_VERSION_DISPLAY_STRING}" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add Version string '${DARWIN_TOOLCHAIN_VERSION}'" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add CFBundleIdentifier string '${DARWIN_TOOLCHAIN_BUNDLE_IDENTIFIER}'" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add ReportProblemURL string '${DARWIN_TOOLCHAIN_REPORT_URL}'" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add Aliases array" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add Aliases:0 string '${DARWIN_TOOLCHAIN_ALIAS}'" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings dict" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:ENABLE_BITCODE string 'NO'" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_DISABLE_REQUIRED_ARCLITE string 'YES'" "${DARWIN_TOOLCHAIN_INFO_PLIST}"
          call ${PLISTBUDDY_BIN} -c "Add OverrideBuildSettings:SWIFT_LINK_OBJC_RUNTIME string 'YES'" "${DARWIN_TOOLCHAIN_INFO_PLIST}"

          call chmod a+r "${DARWIN_TOOLCHAIN_INFO_PLIST}"

          if [[ "${DARWIN_TOOLCHAIN_APPLICATION_CERT}" ]] ; then
            echo "-- Codesign xctoolchain --"
            call "${SWIFT_SOURCE_DIR}/utils/toolchain-codesign" "${DARWIN_TOOLCHAIN_APPLICATION_CERT}" "${host_install_destdir}${TOOLCHAIN_PREFIX}/" 
          fi
          if [[ "${DARWIN_TOOLCHAIN_INSTALLER_PACKAGE}" ]] ; then
            echo "-- Create Installer --"
            call "${SWIFT_SOURCE_DIR}/utils/toolchain-installer" "${host_install_destdir}${TOOLCHAIN_PREFIX}/" "${DARWIN_TOOLCHAIN_BUNDLE_IDENTIFIER}" \
                "${DARWIN_TOOLCHAIN_INSTALLER_CERT}" "${DARWIN_TOOLCHAIN_INSTALLER_PACKAGE}" "${DARWIN_TOOLCHAIN_INSTALL_LOCATION}" \
                "${DARWIN_TOOLCHAIN_VERSION}" "${SWIFT_SOURCE_DIR}/utils/darwin-installer-scripts"
          fi 

          # host_install_destdir contains the toolchain prefix.
          # We want to create the package in host_install_destdir_nonprefixed.
          with_pushd "${host_install_destdir}" \
              call tar -c -z -f "${package_for_host}" "${TOOLCHAIN_PREFIX/#\/}"
        else
            # tar on OS X doesn't support --owner/--group.
            if [[ "$(uname -s)" == "Darwin" ]] ; then
                with_pushd "${host_install_destdir}" \
                    tar -c -z -f "${package_for_host}" "${host_install_prefix/#\/}"
            else
                with_pushd "${host_install_destdir}" \
                    tar -c -z -f "${package_for_host}" --owner=0 --group=0 "${host_install_prefix/#\/}"
            fi
        fi
        if [[ "${TEST_INSTALLABLE_PACKAGE}" ]] ; then
            PKG_TESTS_SOURCE_DIR="${WORKSPACE}/swift-integration-tests"
            PKG_TESTS_SANDBOX_PARENT="$(build_directory swift_package_sandbox_${host} none)"
            PKG_TESTS_TEMPS="${PKG_TESTS_SANDBOX_PARENT}"/"tests"

            if [[ "${host}" == "macosx-"* ]] ; then
                PKG_TESTS_SANDBOX="${PKG_TESTS_SANDBOX_PARENT}"/"${TOOLCHAIN_PREFIX}"
            else # Linux
                PKG_TESTS_SANDBOX="${PKG_TESTS_SANDBOX_PARENT}"
            fi

            LIT_EXECUTABLE_PATH="${LLVM_SOURCE_DIR}/utils/lit/lit.py"
            FILECHECK_EXECUTABLE_PATH="$(build_directory_bin ${LOCAL_HOST} llvm)/FileCheck"
            echo "-- Test Installable Package --"
            call rm -rf "${PKG_TESTS_SANDBOX_PARENT}"
            call mkdir -p "${PKG_TESTS_SANDBOX}"
            with_pushd "${PKG_TESTS_SANDBOX_PARENT}" \
                call tar xzf "${package_for_host}"

            with_pushd "${PKG_TESTS_SOURCE_DIR}" \
                call python "${LIT_EXECUTABLE_PATH}" . -sv --param package-path="${PKG_TESTS_SANDBOX}" --param filecheck="${FILECHECK_EXECUTABLE_PATH}" --param test-exec-root="${PKG_TESTS_TEMPS}"
        fi
    fi
}

# Build and test packages.
for host in "${ALL_HOSTS[@]}"; do
    
    # Check if we should perform this action.
    if ! [[ $(should_execute_action "${host}-package") ]]; then
        continue
    fi
    
    if [[ $(should_include_host_in_lipo ${host}) ]]; then
            continue
    fi    
    
    build_and_test_installable_package ${host}
done

# Lipo those products which require it, optionally build and test an installable package.
if [[ ${#LIPO_SRC_DIRS[@]} -gt 0 ]]; then
    # This is from multiple hosts; Which host should we say it is? 
    # Let's call it 'merged-hosts' so that we can identify it.
    mergedHost="merged-hosts"
    
    # Check if we should perform this action.
    if ! [[ $(should_execute_action "${mergedHost}-lipo") ]]; then
        continue
    fi
    
    echo "--- Merging and running lipo ---"
    
    call "${SWIFT_SOURCE_DIR}"/utils/recursive-lipo --lipo=$(xcrun_find_tool lipo) --copy-subdirs="$(get_host_install_prefix ${host})lib/swift $(get_host_install_prefix ${host})lib/swift_static" --destination="$(get_host_install_destdir ${mergedHost})" ${LIPO_SRC_DIRS[@]}

    # Build and test the lipo-ed package.
    build_and_test_installable_package ${mergedHost}
fi
# END
